Merge "Improve IME perf test show/hide stability" into sc-dev am: b65f67968d am: 649788a5f9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14753630

Change-Id: Id209a154b01d8b0f5526f8cb994dbfc8495a4f23
diff --git a/Android.bp b/Android.bp
index f23ae53..e516ac7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -111,6 +111,7 @@
         ":framework_native_aidl",
         ":gatekeeper_aidl",
         ":gsiservice_aidl",
+        ":guiconstants_aidl",
         ":idmap2_aidl",
         ":idmap2_core_aidl",
         ":incidentcompanion_aidl",
@@ -327,6 +328,8 @@
     ],
     sdk_version: "core_platform",
     static_libs: [
+        // TODO(b/184162091)
+        "android.hardware.soundtrigger3-V1-java",
         "bouncycastle-repackaged-unbundled",
         "framework-internal-utils",
         // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
diff --git a/OWNERS b/OWNERS
index 4970dd1..03cfac9 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,23 +1,23 @@
 # This top-level list should remain narrowly defined as team leads; individual
 # teams are strongly encouraged to define narrower OWNERS files at deeper
 # levels within the source tree; see OWNERS.md for more details
-akulian@google.com
-dsandler@android.com
-dsandler@google.com
-hackbod@android.com
-hackbod@google.com
-jjaggi@google.com
-jsharkey@android.com
-jsharkey@google.com
-lorenzo@google.com
-michaelwr@google.com
-nandana@google.com
-narayan@google.com
-ogunwale@google.com
-roosa@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
-yamasani@google.com
+akulian@google.com #{LAST_RESORT_SUGGESTION}
+dsandler@android.com #{LAST_RESORT_SUGGESTION}
+dsandler@google.com #{LAST_RESORT_SUGGESTION}
+hackbod@android.com #{LAST_RESORT_SUGGESTION}
+hackbod@google.com #{LAST_RESORT_SUGGESTION}
+jjaggi@google.com #{LAST_RESORT_SUGGESTION}
+jsharkey@android.com #{LAST_RESORT_SUGGESTION}
+jsharkey@google.com #{LAST_RESORT_SUGGESTION}
+lorenzo@google.com #{LAST_RESORT_SUGGESTION}
+michaelwr@google.com #{LAST_RESORT_SUGGESTION}
+nandana@google.com #{LAST_RESORT_SUGGESTION}
+narayan@google.com #{LAST_RESORT_SUGGESTION}
+ogunwale@google.com #{LAST_RESORT_SUGGESTION}
+roosa@google.com #{LAST_RESORT_SUGGESTION}
+svetoslavganov@android.com #{LAST_RESORT_SUGGESTION}
+svetoslavganov@google.com #{LAST_RESORT_SUGGESTION}
+yamasani@google.com #{LAST_RESORT_SUGGESTION}
 
 # API changes are already covered by API-Review+1 (http://mdb/android-api-council)
 # via https://android.git.corp.google.com/All-Projects/+/refs/meta/config/rules.pl.
@@ -31,3 +31,5 @@
 per-file ApiDocs.bp = file:platform/build/soong:/OWNERS
 per-file StubLibraries.bp = file:platform/build/soong:/OWNERS
 per-file ProtoLibraries.bp = file:platform/build/soong:/OWNERS
+per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
+per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index 7e3cc27..db5ba2f 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -98,7 +98,7 @@
     },
     // Protos have lots of MissingOverride and similar.
     errorprone: {
-        javacflags: ["-XepDisableAllChecks"],
+        enabled: false,
     },
 }
 
@@ -124,6 +124,10 @@
         "libs/incident/proto/android/os/**/*.proto",
         ":service-permission-protos",
     ],
+    // Protos have lots of MissingOverride and similar.
+    errorprone: {
+        enabled: false,
+    },
 }
 
 // ====  java proto device library (for test only)  ==============================
@@ -150,7 +154,7 @@
     sdk_version: "core_current",
     // Protos have lots of MissingOverride and similar.
     errorprone: {
-        javacflags: ["-XepDisableAllChecks"],
+        enabled: false,
     },
 }
 
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 941a1fa..44c55c2 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -410,7 +410,7 @@
     ],
     static_libs: [
         "android-non-updatable.stubs.module_lib",
-        "art.module.public.api.stubs",
+        "art.module.public.api.stubs.module_lib",
     ],
     dist: {
         dir: "apistubs/android/module-lib",
diff --git a/apct-tests/perftests/core/apps/reources_manager/Android.bp b/apct-tests/perftests/core/apps/reources_manager/Android.bp
index 85dd0c4..766b8c4 100644
--- a/apct-tests/perftests/core/apps/reources_manager/Android.bp
+++ b/apct-tests/perftests/core/apps/reources_manager/Android.bp
@@ -23,15 +23,15 @@
 
 android_test_helper_app {
     name: "LargeResourcesCompressed",
-    static_libs: [ "androidx.appcompat_appcompat" ],
+    static_libs: ["androidx.appcompat_appcompat"],
 }
 
 genrule {
     name: "LargeResourcesUncompressed",
-    srcs: [ ":LargeResourcesCompressed" ],
+    srcs: [":LargeResourcesCompressed"],
     out: ["LargeResourcesUncompressed.apk"],
-    cmd: "cp $(in) $(out) && unzip -o $(out) resources.arsc"
-         + " && zip $(out) resources.arsc"
+    cmd: "cp $(in) $(out) && unzip -o $(out) resources.arsc -d $(genDir)" +
+        " && zip -j $(out) $(genDir)/resources.arsc",
 }
 
 java_library {
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 917753e..c967e51 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -31,6 +31,6 @@
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
-    data: [":perfetto_artifacts"],
+    data: ["trace_configs/*"],
     certificate: "platform",
 }
diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml
index 9553304..63e5983 100644
--- a/apct-tests/perftests/multiuser/AndroidManifest.xml
+++ b/apct-tests/perftests/multiuser/AndroidManifest.xml
@@ -20,10 +20,12 @@
 
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <application>
diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml
index fbe5892..8e342f3 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -26,7 +26,7 @@
     <!-- Needed for pushing the trace config file -->
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+        <option name="push-file" key="trace_config_multi_user.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
         <!--Install the content provider automatically when we push some file in sdcard folder.-->
         <!--Needed to avoid the installation during the test suite.-->
         <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index b1c42a9..42ef80c 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -145,9 +145,11 @@
     @Test
     public void createUser() {
         while (mRunner.keepRunning()) {
+            Log.i(TAG, "Starting timer");
             final int userId = createUserNoFlags();
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -156,6 +158,7 @@
     @Test
     public void createAndStartUser() throws RemoteException {
         while (mRunner.keepRunning()) {
+            Log.i(TAG, "Starting timer");
             final int userId = createUserNoFlags();
 
             final CountDownLatch latch = new CountDownLatch(1);
@@ -166,6 +169,7 @@
             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -181,12 +185,14 @@
             final int userId = createUserNoFlags();
             final CountDownLatch latch = new CountDownLatch(1);
             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             mIam.startUserInBackground(userId);
             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -200,12 +206,14 @@
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             // Waits for UserState.mUnlockProgress.finish().
             startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -217,11 +225,13 @@
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
             final int userId = createUserNoFlags();
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             switchUser(userId);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(userId);
             mRunner.resumeTiming();
@@ -237,6 +247,7 @@
             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
             final CountDownLatch latch = new CountDownLatch(1);
             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             mAm.switchUser(testUser);
@@ -244,6 +255,7 @@
 
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(testUser);
             mRunner.resumeTiming();
@@ -257,11 +269,13 @@
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             switchUser(testUser);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(testUser);
             mRunner.resumeTiming();
@@ -277,11 +291,13 @@
             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
             mIam.startUserInBackground(userId);
             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             stopUser(userId, false);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -295,12 +311,14 @@
             final int userId = createUserNoFlags();
             final CountDownLatch latch = new CountDownLatch(1);
             registerUserSwitchObserver(null, latch, userId);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             mAm.switchUser(userId);
             waitForLatch("Failed to achieve onLockedBootComplete for user " + userId, latch);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             switchUserNoCheck(startUser);
             removeUser(userId);
             mRunner.resumeTiming();
@@ -326,12 +344,14 @@
             }, new IntentFilter(Intent.ACTION_USER_STOPPED));
             final CountDownLatch switchLatch = new CountDownLatch(1);
             registerUserSwitchObserver(switchLatch, null, startUser);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             mAm.switchUser(startUser);
             waitForLatch("Failed to achieve ACTION_USER_STOPPED for user " + userId, latch);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             try {
                 switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
@@ -348,9 +368,11 @@
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
+            Log.i(TAG, "Starting timer");
             final int userId = createManagedProfile();
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
             removeUser(userId);
             mRunner.resumeTiming();
@@ -365,11 +387,13 @@
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -386,11 +410,13 @@
             // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
             startUserInBackgroundAndWaitForUnlock(userId);
             stopUser(userId, true);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             startUserInBackgroundAndWaitForUnlock(userId);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -408,12 +434,14 @@
             final int userId = createManagedProfile();
             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -438,12 +466,14 @@
             startApp(userId, DUMMY_PACKAGE_NAME);
             stopUser(userId, true);
             SystemClock.sleep(1_000); // 1 second cool-down before re-starting profile.
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -457,11 +487,13 @@
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -478,6 +510,7 @@
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             final int userId = createManagedProfile();
@@ -486,6 +519,7 @@
             startApp(userId, DUMMY_PACKAGE_NAME);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -500,11 +534,13 @@
             mRunner.pauseTiming();
             final int userId = createManagedProfile();
             startUserInBackgroundAndWaitForUnlock(userId);
+            Log.i(TAG, "Starting timer");
             mRunner.resumeTiming();
 
             stopUser(userId, true);
 
             mRunner.pauseTiming();
+            Log.i(TAG, "Stopping timer");
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -523,11 +559,13 @@
             while (mRunner.keepRunning()) {
                 mRunner.pauseTiming();
                 final int userId = createManagedProfile();
+                Log.i(TAG, "Starting timer");
                 mRunner.resumeTiming();
 
                 startUserInBackgroundAndWaitForUnlock(userId);
 
                 mRunner.pauseTiming();
+                Log.i(TAG, "Stopping timer");
                 removeUser(userId);
                 mRunner.resumeTiming();
             }
@@ -546,11 +584,13 @@
             while (mRunner.keepRunning()) {
                 mRunner.pauseTiming();
                 final int userId = createManagedProfile();
+                Log.i(TAG, "Starting timer");
                 mRunner.resumeTiming();
 
                 startUserInBackgroundAndWaitForUnlock(userId);
 
                 mRunner.pauseTiming();
+                Log.i(TAG, "Stopping timer");
                 removeUser(userId);
                 mRunner.resumeTiming();
             }
diff --git a/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto
new file mode 100644
index 0000000..14a3f8f
--- /dev/null
+++ b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto
@@ -0,0 +1,154 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 1000
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 10000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers {
+  size_kb: 32768
+  fill_policy: RING_BUFFER
+}
+
+# procfs polling
+buffers {
+  size_kb: 8192
+  fill_policy: RING_BUFFER
+}
+
+data_sources {
+  config {
+    name: "linux.ftrace"
+    target_buffer: 0
+    ftrace_config {
+      # These parameters affect only the kernel trace buffer size and how
+      # frequently it gets moved into the userspace buffer defined above.
+      buffer_size_kb: 16384
+      drain_period_ms: 250
+
+      # Store certain high-volume "sched" ftrace events in a denser format
+      # (falling back to the default format if not supported by the tracer).
+      compact_sched {
+        enabled: true
+      }
+
+      # Enables symbol name resolution against /proc/kallsyms
+      symbolize_ksyms: true
+
+      # We need to do process tracking to ensure kernel ftrace events targeted at short-lived
+      # threads are associated correctly
+      ftrace_events: "task/task_newtask"
+      ftrace_events: "task/task_rename"
+      ftrace_events: "sched/sched_process_exit"
+      ftrace_events: "sched/sched_process_free"
+
+      # Memory events
+      ftrace_events: "rss_stat"
+      ftrace_events: "ion_heap_shrink"
+      ftrace_events: "ion_heap_grow"
+      ftrace_events: "ion/ion_stat"
+      ftrace_events: "dmabuf_heap/dma_heap_stat"
+      ftrace_events: "oom_score_adj_update"
+      ftrace_events: "gpu_mem/gpu_mem_total"
+
+      # Old (kernel) LMK
+      ftrace_events: "lowmemorykiller/lowmemory_kill"
+
+      atrace_apps: "*"
+
+      atrace_categories: "am"
+      atrace_categories: "bionic"
+      atrace_categories: "camera"
+      atrace_categories: "wm"
+      atrace_categories: "dalvik"
+      atrace_categories: "sched"
+      atrace_categories: "freq"
+      atrace_categories: "gfx"
+      atrace_categories: "view"
+      atrace_categories: "webview"
+      atrace_categories: "input"
+      atrace_categories: "hal"
+      atrace_categories: "binder_driver"
+      atrace_categories: "sync"
+      atrace_categories: "workq"
+      atrace_categories: "res"
+
+    }
+  }
+}
+
+data_sources: {
+  config {
+    name: "android.gpu.memory"
+    target_buffer: 0
+  }
+}
+
+data_sources {
+  config {
+    name: "linux.process_stats"
+    target_buffer: 1
+    process_stats_config {
+      proc_stats_poll_ms: 10000
+    }
+  }
+}
+
+data_sources {
+  config {
+    name: "linux.sys_stats"
+    target_buffer: 1
+    sys_stats_config {
+      meminfo_period_ms: 1000
+      meminfo_counters: MEMINFO_MEM_TOTAL
+      meminfo_counters: MEMINFO_MEM_FREE
+      meminfo_counters: MEMINFO_MEM_AVAILABLE
+      meminfo_counters: MEMINFO_BUFFERS
+      meminfo_counters: MEMINFO_CACHED
+      meminfo_counters: MEMINFO_SWAP_CACHED
+      meminfo_counters: MEMINFO_ACTIVE
+      meminfo_counters: MEMINFO_INACTIVE
+      meminfo_counters: MEMINFO_ACTIVE_ANON
+      meminfo_counters: MEMINFO_INACTIVE_ANON
+      meminfo_counters: MEMINFO_ACTIVE_FILE
+      meminfo_counters: MEMINFO_INACTIVE_FILE
+      meminfo_counters: MEMINFO_UNEVICTABLE
+      meminfo_counters: MEMINFO_SWAP_TOTAL
+      meminfo_counters: MEMINFO_SWAP_FREE
+      meminfo_counters: MEMINFO_DIRTY
+      meminfo_counters: MEMINFO_WRITEBACK
+      meminfo_counters: MEMINFO_ANON_PAGES
+      meminfo_counters: MEMINFO_MAPPED
+      meminfo_counters: MEMINFO_SHMEM
+    }
+  }
+}
+
+data_sources: {
+  config: {
+    name: "android.surfaceflinger.frametimeline"
+  }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index e192861..73bff08 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -266,9 +266,9 @@
     public void sendFullStatusReport(Instrumentation instrumentation, String key) {
         Log.i(TAG, key + summaryLine());
         Bundle status = new Bundle();
-        status.putLong(key + "_median", median());
-        status.putLong(key + "_mean", mean());
-        status.putLong(key + "_min", min());
+        status.putLong(key + "_median (ns)", median());
+        status.putLong(key + "_mean (ns)", mean());
+        status.putLong(key + "_min (ns)", min());
         status.putLong(key + "_standardDeviation", standardDeviation());
         instrumentation.sendStatus(Activity.RESULT_OK, status);
     }
diff --git a/apex/jobscheduler/framework/java/android/app/tare/OWNERS b/apex/jobscheduler/framework/java/android/app/tare/OWNERS
new file mode 100644
index 0000000..217a5ed
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/app/tare/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS
\ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 5a13a84..143c0f1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -804,28 +804,42 @@
             @WorkType final int workType) {
         final List<StateController> controllers = mService.mControllers;
         final int numControllers = controllers.size();
-        for (int ic = 0; ic < numControllers; ic++) {
-            controllers.get(ic).prepareForExecutionLocked(jobStatus);
-        }
-        final PackageStats packageStats =
-                getPkgStatsLocked(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
-        packageStats.adjustStagedCount(false, jobStatus.shouldTreatAsExpeditedJob());
-        if (!worker.executeRunnableJob(jobStatus, workType)) {
-            Slog.e(TAG, "Error executing " + jobStatus);
-            mWorkCountTracker.onStagedJobFailed(workType);
+        final PowerManager.WakeLock wl =
+                mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, jobStatus.getTag());
+        wl.setWorkSource(mService.deriveWorkSource(
+                jobStatus.getSourceUid(), jobStatus.getSourcePackageName()));
+        wl.setReferenceCounted(false);
+        // Since the quota controller will start counting from the time prepareForExecutionLocked()
+        // is called, hold a wakelock to make sure the CPU doesn't suspend between that call and
+        // when the service actually starts.
+        wl.acquire();
+        try {
             for (int ic = 0; ic < numControllers; ic++) {
-                controllers.get(ic).unprepareFromExecutionLocked(jobStatus);
+                controllers.get(ic).prepareForExecutionLocked(jobStatus);
             }
-        } else {
-            mRunningJobs.add(jobStatus);
-            mWorkCountTracker.onJobStarted(workType);
-            packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
-            mActivePkgStats.add(
-                    jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), packageStats);
-        }
-        final List<JobStatus> pendingJobs = mService.mPendingJobs;
-        if (pendingJobs.remove(jobStatus)) {
-            mService.mJobPackageTracker.noteNonpending(jobStatus);
+            final PackageStats packageStats = getPkgStatsLocked(
+                    jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+            packageStats.adjustStagedCount(false, jobStatus.shouldTreatAsExpeditedJob());
+            if (!worker.executeRunnableJob(jobStatus, workType)) {
+                Slog.e(TAG, "Error executing " + jobStatus);
+                mWorkCountTracker.onStagedJobFailed(workType);
+                for (int ic = 0; ic < numControllers; ic++) {
+                    controllers.get(ic).unprepareFromExecutionLocked(jobStatus);
+                }
+            } else {
+                mRunningJobs.add(jobStatus);
+                mWorkCountTracker.onJobStarted(workType);
+                packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob());
+                mActivePkgStats.add(
+                        jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
+                        packageStats);
+            }
+            final List<JobStatus> pendingJobs = mService.mPendingJobs;
+            if (pendingJobs.remove(jobStatus)) {
+                mService.mJobPackageTracker.noteNonpending(jobStatus);
+            }
+        } finally {
+            wl.release();
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 78670c7..72d8e72 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -143,6 +143,7 @@
  *
  * Note on locking: Any operations that manipulate {@link #mJobs} need to lock on that object.
  * Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
+ *
  * @hide
  */
 public class JobSchedulerService extends com.android.server.SystemService
@@ -201,7 +202,7 @@
     };
 
     @VisibleForTesting
-    public static Clock sElapsedRealtimeClock =  new MySimpleClock(ZoneOffset.UTC) {
+    public static Clock sElapsedRealtimeClock = new MySimpleClock(ZoneOffset.UTC) {
         @Override
         public long millis() {
             return SystemClock.elapsedRealtime();
@@ -315,7 +316,7 @@
     /**
      * Which uids are currently performing backups, so we shouldn't allow their jobs to run.
      */
-    final SparseIntArray mBackingUpUids = new SparseIntArray();
+    private final SparseBooleanArray mBackingUpUids = new SparseBooleanArray();
 
     /**
      * Cache of debuggable app status.
@@ -601,7 +602,7 @@
                             KEY_API_QUOTA_SCHEDULE_COUNT, DEFAULT_API_QUOTA_SCHEDULE_COUNT));
             API_QUOTA_SCHEDULE_WINDOW_MS = DeviceConfig.getLong(
                     DeviceConfig.NAMESPACE_JOB_SCHEDULER,
-                KEY_API_QUOTA_SCHEDULE_WINDOW_MS, DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS);
+                    KEY_API_QUOTA_SCHEDULE_WINDOW_MS, DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS);
             API_QUOTA_SCHEDULE_THROW_EXCEPTION = DeviceConfig.getBoolean(
                     DeviceConfig.NAMESPACE_JOB_SCHEDULER,
                     KEY_API_QUOTA_SCHEDULE_THROW_EXCEPTION,
@@ -812,9 +813,10 @@
                                 try {
                                     final int userId = UserHandle.getUserId(pkgUid);
                                     IPackageManager pm = AppGlobals.getPackageManager();
-                                    final int state = pm.getApplicationEnabledSetting(pkgName, userId);
+                                    final int state =
+                                            pm.getApplicationEnabledSetting(pkgName, userId);
                                     if (state == COMPONENT_ENABLED_STATE_DISABLED
-                                            || state ==  COMPONENT_ENABLED_STATE_DISABLED_USER) {
+                                            || state == COMPONENT_ENABLED_STATE_DISABLED_USER) {
                                         if (DEBUG) {
                                             Slog.d(TAG, "Removing jobs for package " + pkgName
                                                     + " in user " + userId);
@@ -830,7 +832,7 @@
                                                     "app disabled");
                                         }
                                     }
-                                } catch (RemoteException|IllegalArgumentException e) {
+                                } catch (RemoteException | IllegalArgumentException e) {
                                     /*
                                      * IllegalArgumentException means that the package doesn't exist.
                                      * This arises when PACKAGE_CHANGED broadcast delivery has lagged
@@ -866,16 +868,15 @@
                     }
                 }
             } else if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
-                int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
                 if (DEBUG) {
-                    Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+                    Slog.d(TAG, "Removing jobs for " + pkgName + " (uid=" + pkgUid + ")");
                 }
                 synchronized (mLock) {
-                    mUidToPackageCache.remove(uidRemoved);
+                    mUidToPackageCache.remove(pkgUid);
                     // There's no guarantee that the process has been stopped by the time we
                     // get here, but since this is generally a user-initiated action, it should
                     // be fine to just put USER instead of UNINSTALL or DISABLED.
-                    cancelJobsForPackageAndUidLocked(pkgName, uidRemoved,
+                    cancelJobsForPackageAndUidLocked(pkgName, pkgUid,
                             JobParameters.STOP_REASON_USER,
                             JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "app uninstalled");
                     for (int c = 0; c < mControllers.size(); ++c) {
@@ -984,8 +985,18 @@
         return mConstants;
     }
 
-    public boolean isChainedAttributionEnabled() {
-        return WorkSource.isChainedBatteryAttributionEnabled(getContext());
+    @NonNull
+    public WorkSource deriveWorkSource(int sourceUid, @Nullable String sourcePackageName) {
+        if (WorkSource.isChainedBatteryAttributionEnabled(getContext())) {
+            WorkSource ws = new WorkSource();
+            ws.createWorkChain()
+                    .addNode(sourceUid, sourcePackageName)
+                    .addNode(Process.SYSTEM_UID, "JobScheduler");
+            return ws;
+        } else {
+            return sourcePackageName == null
+                    ? new WorkSource(sourceUid) : new WorkSource(sourceUid, sourcePackageName);
+        }
     }
 
     @Nullable
@@ -1133,7 +1144,7 @@
                 if (mJobs.countJobsForUid(uId) > MAX_JOBS_PER_APP) {
                     Slog.w(TAG, "Too many jobs for uid " + uId);
                     throw new IllegalStateException("Apps may not schedule more than "
-                                + MAX_JOBS_PER_APP + " distinct jobs");
+                            + MAX_JOBS_PER_APP + " distinct jobs");
                 }
             }
 
@@ -1669,6 +1680,7 @@
 
     /**
      * Called when we want to remove a JobStatus object that we've finished executing.
+     *
      * @return true if the job was removed.
      */
     private boolean stopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
@@ -1679,7 +1691,7 @@
         // Remove from store as well as controllers.
         final boolean removed = mJobs.remove(jobStatus, removeFromPersisted);
         if (removed && mReadyToRock) {
-            for (int i=0; i<mControllers.size(); i++) {
+            for (int i = 0; i < mControllers.size(); i++) {
                 StateController controller = mControllers.get(i);
                 controller.maybeStopTrackingJobLocked(jobStatus, incomingJob, false);
             }
@@ -1723,7 +1735,6 @@
      * @param failureToReschedule Provided job status that we will reschedule.
      * @return A newly instantiated JobStatus with the same constraints as the last job except
      * with adjusted timing constraints.
-     *
      * @see #maybeQueueReadyJobsForExecutionLocked
      */
     @VisibleForTesting
@@ -1765,7 +1776,7 @@
             newJob.setOriginalLatestRunTimeElapsed(
                     failureToReschedule.getOriginalLatestRunTimeElapsed());
         }
-        for (int ic=0; ic<mControllers.size(); ic++) {
+        for (int ic = 0; ic < mControllers.size(); ic++) {
             StateController controller = mControllers.get(ic);
             controller.rescheduleForFailureLocked(newJob, failureToReschedule);
         }
@@ -2283,6 +2294,7 @@
             runnableJobs.clear();
         }
     }
+
     private final MaybeReadyJobQueueFunctor mMaybeQueueFunctor = new MaybeReadyJobQueueFunctor();
 
     @GuardedBy("mLock")
@@ -2342,7 +2354,7 @@
 
         final boolean jobExists = mJobs.containsJob(job);
         final boolean userStarted = areUsersStartedLocked(job);
-        final boolean backingUp = mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0;
+        final boolean backingUp = mBackingUpUids.get(job.getSourceUid());
 
         if (DEBUG) {
             Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
@@ -2417,7 +2429,7 @@
 
         final boolean jobExists = mJobs.containsJob(job);
         final boolean userStarted = areUsersStartedLocked(job);
-        final boolean backingUp = mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0;
+        final boolean backingUp = mBackingUpUids.get(job.getSourceUid());
 
         if (DEBUG) {
             Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString()
@@ -2537,7 +2549,7 @@
                 // No need to actually do anything here, since for a full backup the
                 // activity manager will kill the process which will kill the job (and
                 // cause it to restart, but now it can't run).
-                mBackingUpUids.put(uid, uid);
+                mBackingUpUids.put(uid, true);
             }
         }
 
@@ -2675,7 +2687,8 @@
      * Binder stub trampoline implementation
      */
     final class JobSchedulerStub extends IJobScheduler.Stub {
-        /** Cache determination of whether a given app can persist jobs
+        /**
+         * Cache determination of whether a given app can persist jobs
          * key is uid of the calling app; value is undetermined/true/false
          */
         private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
@@ -2956,8 +2969,7 @@
         public List<JobInfo> getStartedJobs() {
             final int uid = Binder.getCallingUid();
             if (uid != Process.SYSTEM_UID) {
-                throw new SecurityException(
-                    "getStartedJobs() is system internal use only.");
+                throw new SecurityException("getStartedJobs() is system internal use only.");
             }
 
             final ArrayList<JobInfo> runningJobs;
@@ -2985,8 +2997,7 @@
         public ParceledListSlice<JobSnapshot> getAllJobSnapshots() {
             final int uid = Binder.getCallingUid();
             if (uid != Process.SYSTEM_UID) {
-                throw new SecurityException(
-                    "getAllJobSnapshots() is system internal use only.");
+                throw new SecurityException("getAllJobSnapshots() is system internal use only.");
             }
             synchronized (mLock) {
                 final ArrayList<JobSnapshot> snapshots = new ArrayList<>(mJobs.size());
@@ -3048,7 +3059,7 @@
 
         synchronized (mLock) {
             boolean foundSome = false;
-            for (int i=0; i<mActiveServices.size(); i++) {
+            for (int i = 0; i < mActiveServices.size(); i++) {
                 final JobServiceContext jc = mActiveServices.get(i);
                 final JobStatus js = jc.getRunningJobLocked();
                 if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
@@ -3187,7 +3198,7 @@
                     printed = true;
                     pw.println("source-user-stopped");
                 }
-                if (mBackingUpUids.indexOfKey(js.getSourceUid()) >= 0) {
+                if (mBackingUpUids.get(js.getSourceUid())) {
                     if (printed) {
                         pw.print(" ");
                     }
@@ -3351,7 +3362,7 @@
                     pw.print(" !active=");
                     pw.print(!mConcurrencyManager.isJobRunningLocked(job));
                     pw.print(" !backingup=");
-                    pw.print(!(mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0));
+                    pw.print(!(mBackingUpUids.get(job.getSourceUid())));
                     pw.print(" comp=");
                     pw.print(isComponentUsable(job));
                     pw.println(")");
@@ -3364,7 +3375,7 @@
             }
             pw.decreaseIndent();
 
-            for (int i=0; i<mControllers.size(); i++) {
+            for (int i = 0; i < mControllers.size(); i++) {
                 pw.println();
                 pw.println(mControllers.get(i).getClass().getSimpleName() + ":");
                 pw.increaseIndent();
@@ -3373,7 +3384,7 @@
             }
 
             boolean overridePrinted = false;
-            for (int i=0; i< mUidPriorityOverride.size(); i++) {
+            for (int i = 0; i < mUidPriorityOverride.size(); i++) {
                 int uid = mUidPriorityOverride.keyAt(i);
                 if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) {
                     if (!overridePrinted) {
@@ -3440,7 +3451,7 @@
             boolean pendingPrinted = false;
             pw.println("Pending queue:");
             pw.increaseIndent();
-            for (int i=0; i<mPendingJobs.size(); i++) {
+            for (int i = 0; i < mPendingJobs.size(); i++) {
                 JobStatus job = mPendingJobs.get(i);
                 if (!predicate.test(job)) {
                     continue;
@@ -3590,7 +3601,8 @@
                         continue;
                     }
 
-                    job.dump(proto, JobSchedulerServiceDumpProto.RegisteredJob.DUMP, true, nowElapsed);
+                    job.dump(proto,
+                            JobSchedulerServiceDumpProto.RegisteredJob.DUMP, true, nowElapsed);
 
                     proto.write(
                             JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_READY_TO_BE_EXECUTED,
@@ -3607,7 +3619,7 @@
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_JOB_CURRENTLY_ACTIVE,
                             mConcurrencyManager.isJobRunningLocked(job));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_UID_BACKING_UP,
-                            mBackingUpUids.indexOfKey(job.getSourceUid()) >= 0);
+                            mBackingUpUids.get(job.getSourceUid()));
                     proto.write(JobSchedulerServiceDumpProto.RegisteredJob.IS_COMPONENT_USABLE,
                             isComponentUsable(job));
 
@@ -3628,7 +3640,7 @@
                 controller.dumpControllerStateLocked(
                         proto, JobSchedulerServiceDumpProto.CONTROLLERS, predicate);
             }
-            for (int i=0; i< mUidPriorityOverride.size(); i++) {
+            for (int i = 0; i < mUidPriorityOverride.size(); i++) {
                 int uid = mUidPriorityOverride.keyAt(i);
                 if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) {
                     long pToken = proto.start(JobSchedulerServiceDumpProto.PRIORITY_OVERRIDES);
@@ -3667,8 +3679,8 @@
                 if (job == null) {
                     final long ijToken = proto.start(ActiveJob.INACTIVE);
 
-                        proto.write(ActiveJob.InactiveJob.TIME_SINCE_STOPPED_MS,
-                                nowElapsed - jsc.mStoppedTime);
+                    proto.write(ActiveJob.InactiveJob.TIME_SINCE_STOPPED_MS,
+                            nowElapsed - jsc.mStoppedTime);
                     if (jsc.mStoppedReason != null) {
                         proto.write(ActiveJob.InactiveJob.STOPPED_REASON,
                                 jsc.mStoppedReason);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 3fa1c12..2ebd1ad 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -42,7 +42,6 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.WorkSource;
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -109,6 +108,7 @@
     private final Object mLock;
     private final IBatteryStats mBatteryStats;
     private final JobPackageTracker mJobPackageTracker;
+    private final PowerManager mPowerManager;
     private PowerManager.WakeLock mWakeLock;
 
     // Execution state.
@@ -205,6 +205,7 @@
         mCallbackHandler = new JobServiceHandler(looper);
         mJobConcurrencyManager = concurrencyManager;
         mCompletedListener = service;
+        mPowerManager = mContext.getSystemService(PowerManager.class);
         mAvailable = true;
         mVerb = VERB_FINISHED;
         mPreferredUid = NO_PREFERRED_UID;
@@ -271,6 +272,12 @@
             // it was inflated from disk with not-yet-coherent delay/deadline bounds.
             job.clearPersistedUtcTimes();
 
+            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, job.getTag());
+            mWakeLock.setWorkSource(
+                    mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
+            mWakeLock.setReferenceCounted(false);
+            mWakeLock.acquire();
+
             mVerb = VERB_BINDING;
             scheduleOpTimeOutLocked();
             final Intent intent = new Intent().setComponent(job.getServiceComponent());
@@ -306,6 +313,7 @@
                 mRunningCallback = null;
                 mParams = null;
                 mExecutionStartTimeElapsed = 0L;
+                mWakeLock.release();
                 mVerb = VERB_FINISHED;
                 removeOpTimeOutLocked();
                 return false;
@@ -495,42 +503,10 @@
                 return;
             }
             this.service = IJobService.Stub.asInterface(service);
-            final PowerManager pm =
-                    (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                    runningJob.getTag());
-            wl.setWorkSource(deriveWorkSource(runningJob));
-            wl.setReferenceCounted(false);
-            wl.acquire();
-
-            // We use a new wakelock instance per job.  In rare cases there is a race between
-            // teardown following job completion/cancellation and new job service spin-up
-            // such that if we simply assign mWakeLock to be the new instance, we orphan
-            // the currently-live lock instead of cleanly replacing it.  Watch for this and
-            // explicitly fast-forward the release if we're in that situation.
-            if (mWakeLock != null) {
-                Slog.w(TAG, "Bound new job " + runningJob + " but live wakelock " + mWakeLock
-                        + " tag=" + mWakeLock.getTag());
-                mWakeLock.release();
-            }
-            mWakeLock = wl;
             doServiceBoundLocked();
         }
     }
 
-    private WorkSource deriveWorkSource(JobStatus runningJob) {
-        final int jobUid = runningJob.getSourceUid();
-        if (WorkSource.isChainedBatteryAttributionEnabled(mContext)) {
-            WorkSource workSource = new WorkSource();
-            workSource.createWorkChain()
-                    .addNode(jobUid, null)
-                    .addNode(android.os.Process.SYSTEM_UID, "JobScheduler");
-            return workSource;
-        } else {
-            return new WorkSource(jobUid);
-        }
-    }
-
     /** If the client service crashes we reschedule this job and clean up. */
     @Override
     public void onServiceDisconnected(ComponentName name) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index e8065aa..41ff9c8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -633,23 +633,34 @@
         }
     }
 
-    private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
+    private boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
             NetworkCapabilities capabilities, Constants constants) {
         // Only consider doing this for unrestricted prefetching jobs
         if (!jobStatus.getJob().isPrefetch() || jobStatus.getStandbyBucket() == RESTRICTED_INDEX) {
             return false;
         }
+        final long estDownloadBytes = jobStatus.getEstimatedNetworkDownloadBytes();
+        if (estDownloadBytes <= 0) {
+            // Need to at least know the estimated download bytes for a prefetch job.
+            return false;
+        }
 
         // See if we match after relaxing any unmetered request
         final NetworkCapabilities.Builder builder =
                 copyCapabilities(jobStatus.getJob().getRequiredNetwork());
         builder.removeCapability(NET_CAPABILITY_NOT_METERED);
-        if (builder.build().satisfiedByNetworkCapabilities(capabilities)) {
-            // TODO: treat this as "maybe" response; need to check quotas
-            return jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
-        } else {
-            return false;
+        if (builder.build().satisfiedByNetworkCapabilities(capabilities)
+                && jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC) {
+            final long opportunisticQuotaBytes =
+                    mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota(
+                            network, NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS);
+            final long estUploadBytes = jobStatus.getEstimatedNetworkUploadBytes();
+            final long estimatedBytes = estDownloadBytes
+                    + (estUploadBytes == JobInfo.NETWORK_BYTES_UNKNOWN ? 0 : estUploadBytes);
+            return opportunisticQuotaBytes >= estimatedBytes;
         }
+
+        return false;
     }
 
     @VisibleForTesting
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index e8ebfb5..98e37a1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -18,11 +18,9 @@
 
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
-import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.AlarmManager.OnAlarmListener;
 import android.content.Context;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.util.IndentingPrintWriter;
@@ -62,8 +60,6 @@
     private long mNextDelayExpiredElapsedMillis;
     private volatile long mLastFiredDelayExpiredElapsedMillis;
 
-    private final boolean mChainedAttributionEnabled;
-
     private AlarmManager mAlarmService = null;
     /** List of tracked jobs, sorted asc. by deadline */
     private final List<JobStatus> mTrackedJobs = new LinkedList<>();
@@ -73,7 +69,6 @@
 
         mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
         mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
-        mChainedAttributionEnabled = mService.isChainedAttributionEnabled();
     }
 
     /**
@@ -117,7 +112,8 @@
             it.add(job);
 
             job.setTrackingController(JobStatus.TRACKING_TIME);
-            WorkSource ws = deriveWorkSource(job.getSourceUid(), job.getSourcePackageName());
+            WorkSource ws =
+                    mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName());
 
             // Only update alarms if the job would be ready with the relevant timing constraint
             // satisfied.
@@ -165,7 +161,7 @@
             } else if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) {
                 // This job's deadline is earlier than the current set alarm. Update the alarm.
                 setDeadlineExpiredAlarmLocked(job.getLatestRunTimeElapsed(),
-                        deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
+                        mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
             }
         }
         if (job.hasTimingDelayConstraint()
@@ -177,7 +173,7 @@
                     && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
                 // This job's delay is earlier than the current set alarm. Update the alarm.
                 setDelayExpiredAlarmLocked(job.getEarliestRunTime(),
-                        deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
+                        mService.deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
             }
         }
     }
@@ -248,7 +244,7 @@
                 }
             }
             setDeadlineExpiredAlarmLocked(nextExpiryTime,
-                    deriveWorkSource(nextExpiryUid, nextExpiryPackageName));
+                    mService.deriveWorkSource(nextExpiryUid, nextExpiryPackageName));
         }
     }
 
@@ -312,19 +308,7 @@
                 mStateChangedListener.onControllerStateChanged();
             }
             setDelayExpiredAlarmLocked(nextDelayTime,
-                    deriveWorkSource(nextDelayUid, nextDelayPackageName));
-        }
-    }
-
-    private WorkSource deriveWorkSource(int uid, @Nullable String packageName) {
-        if (mChainedAttributionEnabled) {
-            WorkSource ws = new WorkSource();
-            ws.createWorkChain()
-                    .addNode(uid, packageName)
-                    .addNode(Process.SYSTEM_UID, "JobScheduler");
-            return ws;
-        } else {
-            return packageName == null ? new WorkSource(uid) : new WorkSource(uid, packageName);
+                    mService.deriveWorkSource(nextDelayUid, nextDelayPackageName));
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
new file mode 100644
index 0000000..f8f0bd0
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import static com.android.server.tare.EconomicPolicy.REGULATION_BASIC_INCOME;
+import static com.android.server.tare.EconomicPolicy.REGULATION_BIRTHRIGHT;
+import static com.android.server.tare.EconomicPolicy.TYPE_ACTION;
+import static com.android.server.tare.EconomicPolicy.TYPE_REWARD;
+import static com.android.server.tare.EconomicPolicy.eventToString;
+import static com.android.server.tare.EconomicPolicy.getEventType;
+import static com.android.server.tare.TareUtils.narcToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.PriorityQueue;
+
+/**
+ * Other half of the IRS. The agent handles the nitty gritty details, interacting directly with
+ * ledgers, carrying out specific events such as tax collection and granting initial balances or
+ * replenishing balances, and tracking ongoing events.
+ */
+class Agent {
+    private static final String TAG = "TARE-" + Agent.class.getSimpleName();
+    private static final boolean DEBUG = InternalResourceService.DEBUG
+            || Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * The maximum amount of time we'll keep a transaction around for.
+     * For now, only keep transactions we actually have a use for. We can increase it if we want
+     * to use older transactions or provide older transactions to apps.
+     */
+    private static final long MAX_TRANSACTION_AGE_MS = 24 * HOUR_IN_MILLIS;
+
+    private static final String ALARM_TAG_LEDGER_CLEANUP = "*tare.ledger_cleanup*";
+
+    private final Object mLock;
+    private final CompleteEconomicPolicy mCompleteEconomicPolicy;
+    private final Handler mHandler;
+    private final InternalResourceService mIrs;
+
+    @GuardedBy("mLock")
+    private final SparseArrayMap<String, Ledger> mLedgers = new SparseArrayMap<>();
+
+    @GuardedBy("mLock")
+    private long mCurrentNarcsInCirculation;
+
+    /**
+     * Listener to track and manage when we remove old transactions from ledgers.
+     */
+    @GuardedBy("mLock")
+    private final LedgerCleanupAlarmListener mLedgerCleanupAlarmListener =
+            new LedgerCleanupAlarmListener();
+
+    private static final int MSG_CLEAN_LEDGER = 1;
+    private static final int MSG_SET_ALARMS = 2;
+
+    Agent(@NonNull InternalResourceService irs,
+            @NonNull CompleteEconomicPolicy completeEconomicPolicy) {
+        mLock = irs.getLock();
+        mIrs = irs;
+        mCompleteEconomicPolicy = completeEconomicPolicy;
+        mHandler = new AgentHandler(TareHandlerThread.get().getLooper());
+    }
+
+    @GuardedBy("mLock")
+    @NonNull
+    private Ledger getLedgerLocked(final int userId, @NonNull final String pkgName) {
+        Ledger ledger = mLedgers.get(userId, pkgName);
+        if (ledger == null) {
+            // TODO: load from disk
+            ledger = new Ledger();
+            mLedgers.add(userId, pkgName, ledger);
+        }
+        return ledger;
+    }
+
+    /** Get an app's current balance, factoring in any currently ongoing events. */
+    @GuardedBy("mLock")
+    long getBalanceLocked(final int userId, @NonNull final String pkgName) {
+        final Ledger ledger = getLedgerLocked(userId, pkgName);
+        long balance = ledger.getCurrentBalance();
+        // TODO: add ongoing events
+        return balance;
+    }
+
+    @GuardedBy("mLock")
+    void noteInstantaneousEventLocked(final int userId, @NonNull final String pkgName,
+            final int eventId, @Nullable String tag) {
+        final long now = System.currentTimeMillis();
+        final Ledger ledger = getLedgerLocked(userId, pkgName);
+
+        final int eventType = getEventType(eventId);
+        switch (eventType) {
+            case TYPE_ACTION:
+                final long actionCost =
+                        mCompleteEconomicPolicy.getCostOfAction(eventId, userId, pkgName);
+
+                recordTransactionLocked(userId, pkgName, ledger,
+                        new Ledger.Transaction(now, now, eventId, tag, -actionCost));
+                break;
+
+            case TYPE_REWARD:
+                final EconomicPolicy.Reward reward = mCompleteEconomicPolicy.getReward(eventId);
+                if (reward != null) {
+                    final long rewardSum = ledger.get24HourSum(eventId, now);
+                    final long rewardVal = Math.max(0,
+                            Math.min(reward.maxDailyReward - rewardSum, reward.instantReward));
+                    recordTransactionLocked(userId, pkgName, ledger,
+                            new Ledger.Transaction(now, now, eventId, tag, rewardVal));
+                }
+                break;
+
+            default:
+                Slog.w(TAG, "Unsupported event type: " + eventType);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void recordTransactionLocked(final int userId, @NonNull final String pkgName,
+            @NonNull Ledger ledger, @NonNull Ledger.Transaction transaction) {
+        final long maxCirculationAllowed = mIrs.getMaxCirculationLocked();
+        final long newArcsInCirculation = mCurrentNarcsInCirculation + transaction.delta;
+        if (transaction.delta > 0 && newArcsInCirculation > maxCirculationAllowed) {
+            final long newDelta = maxCirculationAllowed - mCurrentNarcsInCirculation;
+            Slog.i(TAG, "Would result in too many credits in circulation. Decreasing transaction "
+                    + eventToString(transaction.eventId)
+                    + (transaction.tag == null ? "" : ":" + transaction.tag)
+                    + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta));
+            transaction = new Ledger.Transaction(
+                    transaction.startTimeMs, transaction.endTimeMs,
+                    transaction.eventId, transaction.tag, newDelta);
+        }
+        final long originalBalance = ledger.getCurrentBalance();
+        if (transaction.delta > 0
+                && originalBalance + transaction.delta
+                > mCompleteEconomicPolicy.getMaxSatiatedBalance()) {
+            final long newDelta = mCompleteEconomicPolicy.getMaxSatiatedBalance() - originalBalance;
+            Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction "
+                    + eventToString(transaction.eventId)
+                    + (transaction.tag == null ? "" : ":" + transaction.tag)
+                    + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta));
+            transaction = new Ledger.Transaction(
+                    transaction.startTimeMs, transaction.endTimeMs,
+                    transaction.eventId, transaction.tag, newDelta);
+        }
+        ledger.recordTransaction(transaction);
+        mCurrentNarcsInCirculation += transaction.delta;
+        if (!mLedgerCleanupAlarmListener.hasAlarmScheduledLocked(userId, pkgName)) {
+            // The earliest transaction won't change until we clean up the ledger, so no point
+            // continuing to reschedule an existing cleanup.
+            final long cleanupAlarmElapsed = SystemClock.elapsedRealtime() + MAX_TRANSACTION_AGE_MS
+                    - (System.currentTimeMillis() - ledger.getEarliestTransaction().endTimeMs);
+            mLedgerCleanupAlarmListener.addAlarmLocked(userId, pkgName, cleanupAlarmElapsed);
+        }
+        // TODO: save changes to disk in a background thread
+        final long newBalance = ledger.getCurrentBalance();
+        if (originalBalance <= 0 && newBalance > 0) {
+            mIrs.postSolvencyChanged(userId, pkgName, true);
+        } else if (originalBalance > 0 && newBalance <= 0) {
+            mIrs.postSolvencyChanged(userId, pkgName, false);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void distributeBasicIncomeLocked(int batteryLevel) {
+        List<PackageInfo> pkgs = mIrs.getInstalledPackages();
+        final long now = System.currentTimeMillis();
+        for (int i = 0; i < pkgs.size(); ++i) {
+            final PackageInfo pkgInfo = pkgs.get(i);
+            final int userId = UserHandle.getUserId(pkgInfo.applicationInfo.uid);
+            final String pkgName = pkgInfo.packageName;
+            Ledger ledger = getLedgerLocked(userId, pkgName);
+            final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
+            final double perc = batteryLevel / 100d;
+            // TODO: maybe don't give credits to bankrupt apps until battery level >= 50%
+            if (ledger.getCurrentBalance() < minBalance) {
+                final long shortfall = minBalance - getBalanceLocked(userId, pkgName);
+                recordTransactionLocked(userId, pkgName, ledger,
+                        new Ledger.Transaction(now, now, REGULATION_BASIC_INCOME,
+                                null, (long) (perc * shortfall)));
+            }
+        }
+    }
+
+    /** Give each app an initial balance. */
+    @GuardedBy("mLock")
+    void grantBirthrightsLocked() {
+        UserManagerInternal userManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+        final int[] userIds = userManagerInternal.getUserIds();
+        for (int userId : userIds) {
+            grantBirthrightsLocked(userId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void grantBirthrightsLocked(final int userId) {
+        PackageManager packageManager = mIrs.getContext().getPackageManager();
+        List<PackageInfo> pkgs = packageManager.getInstalledPackagesAsUser(0, userId);
+        final long maxBirthright =
+                mIrs.getMaxCirculationLocked() / mIrs.getInstalledPackages().size();
+        final long now = System.currentTimeMillis();
+
+        for (int i = 0; i < pkgs.size(); ++i) {
+            final PackageInfo packageInfo = pkgs.get(i);
+            final String pkgName = packageInfo.packageName;
+            final Ledger ledger = getLedgerLocked(userId, pkgName);
+            if (ledger.getCurrentBalance() > 0) {
+                // App already got credits somehow. Move along.
+                Slog.wtf(TAG, "App " + pkgName + " had credits before economy was set up");
+                continue;
+            }
+
+            recordTransactionLocked(userId, pkgName, ledger,
+                    new Ledger.Transaction(now, now, REGULATION_BIRTHRIGHT, null,
+                            Math.min(maxBirthright, mIrs.getMinBalanceLocked(userId, pkgName))));
+        }
+    }
+
+    @GuardedBy("mLock")
+    void grantBirthrightLocked(final int userId, @NonNull final String pkgName) {
+        final Ledger ledger = getLedgerLocked(userId, pkgName);
+        if (ledger.getCurrentBalance() > 0) {
+            Slog.wtf(TAG, "App " + pkgName + " had credits as soon as it was installed");
+            // App already got credits somehow. Move along.
+            return;
+        }
+
+        List<PackageInfo> pkgs = mIrs.getInstalledPackages();
+        final int numPackages = pkgs.size();
+        final long maxBirthright = mIrs.getMaxCirculationLocked() / numPackages;
+        final long now = System.currentTimeMillis();
+
+        recordTransactionLocked(userId, pkgName, ledger,
+                new Ledger.Transaction(now, now, REGULATION_BIRTHRIGHT, null,
+                        Math.min(maxBirthright, mIrs.getMinBalanceLocked(userId, pkgName))));
+    }
+
+    @GuardedBy("mLock")
+    void onPackageRemovedLocked(final int userId, @NonNull final String pkgName) {
+        reclaimAssetsLocked(userId, pkgName);
+        mLedgerCleanupAlarmListener.removeAlarmLocked(userId, pkgName);
+    }
+
+    /**
+     * Reclaims any ARCs granted to the app, making them available to other apps. Also deletes the
+     * app's ledger and stops any ongoing event tracking.
+     */
+    @GuardedBy("mLock")
+    private void reclaimAssetsLocked(final int userId, @NonNull final String pkgName) {
+        Ledger ledger = getLedgerLocked(userId, pkgName);
+        if (ledger.getCurrentBalance() != 0) {
+            mCurrentNarcsInCirculation -= ledger.getCurrentBalance();
+        }
+        // TODO: delete ledger entry from disk
+        mLedgers.delete(userId, pkgName);
+    }
+
+    @GuardedBy("mLock")
+    void onUserRemovedLocked(final int userId, @NonNull final List<String> pkgNames) {
+        reclaimAssetsLocked(userId, pkgNames);
+        mLedgerCleanupAlarmListener.removeAlarmsLocked(userId);
+    }
+
+    @GuardedBy("mLock")
+    private void reclaimAssetsLocked(final int userId, @NonNull final List<String> pkgNames) {
+        for (int i = 0; i < pkgNames.size(); ++i) {
+            reclaimAssetsLocked(userId, pkgNames.get(i));
+        }
+    }
+
+    /**
+     * An {@link AlarmManager.OnAlarmListener} that will queue up all pending alarms and only
+     * schedule one alarm for the earliest alarm.
+     */
+    private abstract class AlarmQueueListener implements AlarmManager.OnAlarmListener {
+        final class Package {
+            public final String packageName;
+            public final int userId;
+
+            Package(int userId, String packageName) {
+                this.userId = userId;
+                this.packageName = packageName;
+            }
+
+            @Override
+            public String toString() {
+                return "<" + userId + ">" + packageName;
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (obj == null) {
+                    return false;
+                }
+                if (this == obj) {
+                    return true;
+                }
+                if (obj instanceof Package) {
+                    Package other = (Package) obj;
+                    return userId == other.userId && Objects.equals(packageName, other.packageName);
+                } else {
+                    return false;
+                }
+            }
+
+            @Override
+            public int hashCode() {
+                return packageName.hashCode() + userId;
+            }
+        }
+
+        class AlarmQueue extends PriorityQueue<Pair<Package, Long>> {
+            AlarmQueue() {
+                super(1, (o1, o2) -> (int) (o1.second - o2.second));
+            }
+
+            boolean contains(@NonNull Package pkg) {
+                Pair[] alarms = toArray(new Pair[size()]);
+                for (int i = alarms.length - 1; i >= 0; --i) {
+                    if (pkg.equals(alarms[i].first)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            /**
+             * Remove any instances of the Package from the queue.
+             *
+             * @return true if an instance was removed, false otherwise.
+             */
+            boolean remove(@NonNull Package pkg) {
+                boolean removed = false;
+                Pair[] alarms = toArray(new Pair[size()]);
+                for (int i = alarms.length - 1; i >= 0; --i) {
+                    if (pkg.equals(alarms[i].first)) {
+                        remove(alarms[i]);
+                        removed = true;
+                    }
+                }
+                return removed;
+            }
+        }
+
+        @GuardedBy("mLock")
+        private final AlarmQueue mAlarmQueue = new AlarmQueue();
+        private final String mAlarmTag;
+        /** Whether to use an exact alarm or an inexact alarm. */
+        private final boolean mExactAlarm;
+        /** The minimum amount of time between check alarms. */
+        private final long mMinTimeBetweenAlarmsMs;
+        /** The next time the alarm is set to go off, in the elapsed realtime timebase. */
+        @GuardedBy("mLock")
+        private long mTriggerTimeElapsed = 0;
+
+        protected AlarmQueueListener(@NonNull String alarmTag, boolean exactAlarm,
+                long minTimeBetweenAlarmsMs) {
+            mAlarmTag = alarmTag;
+            mExactAlarm = exactAlarm;
+            mMinTimeBetweenAlarmsMs = minTimeBetweenAlarmsMs;
+        }
+
+        @GuardedBy("mLock")
+        boolean hasAlarmScheduledLocked(int userId, @NonNull String pkgName) {
+            final Package pkg = new Package(userId, pkgName);
+            return mAlarmQueue.contains(pkg);
+        }
+
+        @GuardedBy("mLock")
+        void addAlarmLocked(int userId, @NonNull String pkgName, long alarmTimeElapsed) {
+            final Package pkg = new Package(userId, pkgName);
+            mAlarmQueue.remove(pkg);
+            mAlarmQueue.offer(new Pair<>(pkg, alarmTimeElapsed));
+            setNextAlarmLocked();
+        }
+
+        @GuardedBy("mLock")
+        void removeAlarmLocked(@NonNull Package pkg) {
+            if (mAlarmQueue.remove(pkg)) {
+                setNextAlarmLocked();
+            }
+        }
+
+        @GuardedBy("mLock")
+        void removeAlarmLocked(int userId, @NonNull String packageName) {
+            removeAlarmLocked(new Package(userId, packageName));
+        }
+
+        @GuardedBy("mLock")
+        void removeAlarmsLocked(int userId) {
+            boolean removed = false;
+            Pair[] alarms = mAlarmQueue.toArray(new Pair[mAlarmQueue.size()]);
+            for (int i = alarms.length - 1; i >= 0; --i) {
+                final Package pkg = (Package) alarms[i].first;
+                if (userId == pkg.userId) {
+                    mAlarmQueue.remove(alarms[i]);
+                    removed = true;
+                }
+            }
+            if (removed) {
+                setNextAlarmLocked();
+            }
+        }
+
+        /** Sets an alarm with {@link AlarmManager} for the earliest alarm in the queue. */
+        @GuardedBy("mLock")
+        void setNextAlarmLocked() {
+            setNextAlarmLocked(SystemClock.elapsedRealtime());
+        }
+
+        /**
+         * Sets an alarm with {@link AlarmManager} for the earliest alarm in the queue, using
+         * {@code earliestTriggerElapsed} as a floor.
+         */
+        @GuardedBy("mLock")
+        private void setNextAlarmLocked(long earliestTriggerElapsed) {
+            if (mAlarmQueue.size() > 0) {
+                final Pair<Package, Long> alarm = mAlarmQueue.peek();
+                final long nextTriggerTimeElapsed = Math.max(earliestTriggerElapsed, alarm.second);
+                // Only schedule the alarm if one of the following is true:
+                // 1. There isn't one currently scheduled
+                // 2. The new alarm is significantly earlier than the previous alarm. If it's
+                // earlier but not significantly so, then we essentially delay the check for some
+                // apps by up to a minute.
+                // 3. The alarm is after the current alarm.
+                if (mTriggerTimeElapsed == 0
+                        || nextTriggerTimeElapsed < mTriggerTimeElapsed - MINUTE_IN_MILLIS
+                        || mTriggerTimeElapsed < nextTriggerTimeElapsed) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Scheduling start alarm at " + nextTriggerTimeElapsed
+                                + " for app " + alarm.first);
+                    }
+                    mHandler.post(() -> {
+                        // Never call out to AlarmManager with the lock held. This sits below AM.
+                        AlarmManager alarmManager =
+                                mIrs.getContext().getSystemService(AlarmManager.class);
+                        if (alarmManager != null) {
+                            if (mExactAlarm) {
+                                alarmManager.setExact(AlarmManager.ELAPSED_REALTIME,
+                                        nextTriggerTimeElapsed, mAlarmTag, this, mHandler);
+                            } else {
+                                alarmManager.setWindow(AlarmManager.ELAPSED_REALTIME,
+                                        nextTriggerTimeElapsed, mMinTimeBetweenAlarmsMs / 2,
+                                        mAlarmTag, this, mHandler);
+                            }
+                        } else {
+                            mHandler.sendEmptyMessageDelayed(MSG_SET_ALARMS, 30_000);
+                        }
+                    });
+                    mTriggerTimeElapsed = nextTriggerTimeElapsed;
+                }
+            } else {
+                mHandler.post(() -> {
+                    // Never call out to AlarmManager with the lock held. This sits below AM.
+                    AlarmManager alarmManager =
+                            mIrs.getContext().getSystemService(AlarmManager.class);
+                    if (alarmManager != null) {
+                        // This should only be null at boot time. No concerns around not
+                        // cancelling if we get null here.
+                        alarmManager.cancel(this);
+                    }
+                });
+                mTriggerTimeElapsed = 0;
+            }
+        }
+
+        @GuardedBy("mLock")
+        protected abstract void processExpiredAlarmLocked(int userId, @NonNull String packageName);
+
+        @Override
+        public void onAlarm() {
+            synchronized (mLock) {
+                final long nowElapsed = SystemClock.elapsedRealtime();
+                while (mAlarmQueue.size() > 0) {
+                    final Pair<Package, Long> alarm = mAlarmQueue.peek();
+                    if (alarm.second <= nowElapsed) {
+                        processExpiredAlarmLocked(alarm.first.userId, alarm.first.packageName);
+                        mAlarmQueue.remove(alarm);
+                    } else {
+                        break;
+                    }
+                }
+                setNextAlarmLocked(nowElapsed + mMinTimeBetweenAlarmsMs);
+            }
+        }
+
+        @GuardedBy("mLock")
+        void dumpLocked(IndentingPrintWriter pw) {
+            pw.print(mAlarmTag);
+            pw.println(" alarms:");
+            pw.increaseIndent();
+
+            if (mAlarmQueue.size() == 0) {
+                pw.println("NOT WAITING");
+            } else {
+                Pair[] alarms = mAlarmQueue.toArray(new Pair[mAlarmQueue.size()]);
+                for (int i = 0; i < alarms.length; ++i) {
+                    final Package pkg = (Package) alarms[i].first;
+                    pw.print(pkg);
+                    pw.print(": ");
+                    pw.print(alarms[i].second);
+                    pw.println();
+                }
+            }
+
+            pw.decreaseIndent();
+        }
+    }
+
+    /** Clean up old transactions from {@link Ledger}s. */
+    private class LedgerCleanupAlarmListener extends AlarmQueueListener {
+        private LedgerCleanupAlarmListener() {
+            // We don't need to run cleanup too frequently.
+            super(ALARM_TAG_LEDGER_CLEANUP, false, HOUR_IN_MILLIS);
+        }
+
+        @Override
+        @GuardedBy("mLock")
+        protected void processExpiredAlarmLocked(int userId, @NonNull String packageName) {
+            mHandler.obtainMessage(MSG_CLEAN_LEDGER, userId, 0, packageName).sendToTarget();
+        }
+    }
+
+    private final class AgentHandler extends Handler {
+        AgentHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_CLEAN_LEDGER: {
+                    final int userId = msg.arg1;
+                    final String pkgName = (String) msg.obj;
+                    synchronized (mLock) {
+                        final Ledger ledger = getLedgerLocked(userId, pkgName);
+                        ledger.removeOldTransactions(MAX_TRANSACTION_AGE_MS);
+                    }
+                }
+                break;
+
+                case MSG_SET_ALARMS: {
+                    synchronized (mLock) {
+                        mLedgerCleanupAlarmListener.setNextAlarmLocked();
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    void dumpLocked(IndentingPrintWriter pw) {
+        pw.print("Current GDP: ");
+        pw.println(narcToString(mCurrentNarcsInCirculation));
+
+        pw.println();
+        mLedgerCleanupAlarmListener.dumpLocked(pw);
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
new file mode 100644
index 0000000..acdf689
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
+import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
+import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
+import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
+import static com.android.server.tare.TareUtils.arcToNarc;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.SparseArray;
+
+/**
+ * Policy defining pricing information and daily ARC requirements and suggestions for
+ * AlarmManager.
+ */
+public class AlarmManagerEconomicPolicy extends EconomicPolicy {
+    public static final int ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE =
+            TYPE_ACTION | POLICY_AM | 0;
+    public static final int ACTION_ALARM_WAKEUP_EXACT =
+            TYPE_ACTION | POLICY_AM | 1;
+    public static final int ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE =
+            TYPE_ACTION | POLICY_AM | 2;
+    public static final int ACTION_ALARM_WAKEUP_INEXACT =
+            TYPE_ACTION | POLICY_AM | 3;
+    public static final int ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE =
+            TYPE_ACTION | POLICY_AM | 4;
+    public static final int ACTION_ALARM_NONWAKEUP_EXACT =
+            TYPE_ACTION | POLICY_AM | 5;
+    public static final int ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE =
+            TYPE_ACTION | POLICY_AM | 6;
+    public static final int ACTION_ALARM_NONWAKEUP_INEXACT =
+            TYPE_ACTION | POLICY_AM | 7;
+    public static final int ACTION_ALARM_CLOCK =
+            TYPE_ACTION | POLICY_AM | 8;
+
+    private static final int[] COST_MODIFIERS = new int[]{
+            COST_MODIFIER_CHARGING,
+            COST_MODIFIER_DEVICE_IDLE,
+            COST_MODIFIER_POWER_SAVE_MODE,
+            COST_MODIFIER_PROCESS_STATE
+    };
+
+    private final SparseArray<Action> mActions = new SparseArray<>();
+    private final SparseArray<Reward> mRewards = new SparseArray<>();
+
+    AlarmManagerEconomicPolicy(InternalResourceService irs) {
+        super(irs);
+        loadActions();
+        loadRewards();
+    }
+
+    @Override
+    long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
+        // TODO: take exemption into account
+        return arcToNarc(160);
+    }
+
+    @Override
+    long getMaxSatiatedBalance() {
+        return arcToNarc(1440);
+    }
+
+
+    @Override
+    long getMaxSatiatedCirculation() {
+        return arcToNarc(52000);
+    }
+
+    @NonNull
+    @Override
+    int[] getCostModifiers() {
+        return COST_MODIFIERS;
+    }
+
+    @Nullable
+    @Override
+    Action getAction(@AppAction int actionId) {
+        return mActions.get(actionId);
+    }
+
+    @Nullable
+    @Override
+    Reward getReward(@UtilityReward int rewardId) {
+        return mRewards.get(rewardId);
+    }
+
+    private void loadActions() {
+        mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
+                new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(5)));
+        mActions.put(ACTION_ALARM_WAKEUP_EXACT,
+                new Action(ACTION_ALARM_WAKEUP_EXACT, arcToNarc(3), arcToNarc(4)));
+        mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
+                new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
+                        arcToNarc(3), arcToNarc(4)));
+        mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
+                new Action(ACTION_ALARM_WAKEUP_INEXACT, arcToNarc(3), arcToNarc(3)));
+        mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
+                new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
+                        arcToNarc(1), arcToNarc(3)));
+        mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
+                new Action(ACTION_ALARM_NONWAKEUP_EXACT, arcToNarc(1), arcToNarc(2)));
+        mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
+                new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
+                        arcToNarc(1), arcToNarc(2)));
+        mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
+                new Action(ACTION_ALARM_NONWAKEUP_INEXACT, arcToNarc(1), arcToNarc(1)));
+        mActions.put(ACTION_ALARM_CLOCK,
+                new Action(ACTION_ALARM_CLOCK, arcToNarc(5), arcToNarc(10)));
+    }
+
+    private void loadRewards() {
+        mRewards.put(REWARD_TOP_ACTIVITY,
+                new Reward(REWARD_TOP_ACTIVITY,
+                        arcToNarc(0), /* .01 arcs */ arcToNarc(1) / 100, arcToNarc(500)));
+        mRewards.put(REWARD_NOTIFICATION_SEEN,
+                new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(3), arcToNarc(0), arcToNarc(60)));
+        mRewards.put(REWARD_NOTIFICATION_INTERACTION,
+                new Reward(REWARD_NOTIFICATION_INTERACTION,
+                        arcToNarc(5), arcToNarc(0), arcToNarc(500)));
+        mRewards.put(REWARD_WIDGET_INTERACTION,
+                new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+        mRewards.put(REWARD_OTHER_USER_INTERACTION,
+                new Reward(REWARD_OTHER_USER_INTERACTION,
+                        arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
new file mode 100644
index 0000000..a627de6
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Slog;
+
+/** Modifier that makes things free when the device is charging. */
+class ChargingModifier extends Modifier {
+    private static final String TAG = "TARE-" + ChargingModifier.class.getSimpleName();
+    private static final boolean DEBUG = InternalResourceService.DEBUG
+            || Log.isLoggable(TAG, Log.DEBUG);
+
+    private final InternalResourceService mIrs;
+    private final ChargingTracker mChargingTracker;
+
+    ChargingModifier(@NonNull InternalResourceService irs) {
+        super();
+        mIrs = irs;
+        mChargingTracker = new ChargingTracker();
+        mChargingTracker.startTracking(irs.getContext());
+    }
+
+    @Override
+    long getModifiedCostToProduce(long ctp) {
+        return modifyValue(ctp);
+    }
+
+    @Override
+    long getModifiedPrice(long price) {
+        return modifyValue(price);
+    }
+
+    private long modifyValue(long val) {
+        if (mChargingTracker.mCharging) {
+            return 0;
+        }
+        return val;
+    }
+
+    @Override
+    void dump(IndentingPrintWriter pw) {
+        pw.print("charging=");
+        pw.println(mChargingTracker.mCharging);
+    }
+
+    private final class ChargingTracker extends BroadcastReceiver {
+        /**
+         * Track whether we're "charging", where charging means that we're ready to commit to
+         * doing work.
+         */
+        private volatile boolean mCharging;
+
+        public void startTracking(@NonNull Context context) {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(BatteryManager.ACTION_CHARGING);
+            filter.addAction(BatteryManager.ACTION_DISCHARGING);
+            context.registerReceiver(this, filter);
+
+            // Initialise tracker state.
+            final BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
+            mCharging = batteryManager.isCharging();
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (BatteryManager.ACTION_CHARGING.equals(action)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Received charging intent, fired @ "
+                            + SystemClock.elapsedRealtime());
+                }
+                if (!mCharging) {
+                    mCharging = true;
+                    mIrs.onDeviceStateChanged();
+                }
+            } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Disconnected from power.");
+                }
+                if (mCharging) {
+                    mCharging = false;
+                    mIrs.onDeviceStateChanged();
+                }
+            }
+        }
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
new file mode 100644
index 0000000..8c56c61
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
+import android.util.SparseArray;
+
+import libcore.util.EmptyArray;
+
+
+/** Combines all enabled policies into one. */
+public class CompleteEconomicPolicy extends EconomicPolicy {
+    private final ArraySet<EconomicPolicy> mEnabledEconomicPolicies = new ArraySet<>();
+    /** Lazily populated set of actions covered by this policy. */
+    private final SparseArray<Action> mActions = new SparseArray<>();
+    /** Lazily populated set of rewards covered by this policy. */
+    private final SparseArray<Reward> mRewards = new SparseArray<>();
+    private final int[] mCostModifiers;
+    private final long mMaxSatiatedBalance;
+    private final long mMaxSatiatedCirculation;
+
+    CompleteEconomicPolicy(@NonNull InternalResourceService irs) {
+        super(irs);
+        mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(irs));
+        mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(irs));
+
+        ArraySet<Integer> costModifiers = new ArraySet<>();
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            final int[] sm = mEnabledEconomicPolicies.valueAt(i).getCostModifiers();
+            for (int s : sm) {
+                costModifiers.add(s);
+            }
+        }
+        mCostModifiers = new int[costModifiers.size()];
+        for (int i = 0; i < costModifiers.size(); ++i) {
+            mCostModifiers[i] = costModifiers.valueAt(i);
+        }
+
+        long max = 0;
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance();
+        }
+        mMaxSatiatedBalance = max;
+
+        max = 0;
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedCirculation();
+        }
+        mMaxSatiatedCirculation = max;
+    }
+
+    @Override
+    public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
+        long min = 0;
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            min += mEnabledEconomicPolicies.valueAt(i).getMinSatiatedBalance(userId, pkgName);
+        }
+        return min;
+    }
+
+    @Override
+    public long getMaxSatiatedBalance() {
+        return mMaxSatiatedBalance;
+    }
+
+    @Override
+    public long getMaxSatiatedCirculation() {
+        return mMaxSatiatedCirculation;
+    }
+
+    @NonNull
+    @Override
+    public int[] getCostModifiers() {
+        return mCostModifiers == null ? EmptyArray.INT : mCostModifiers;
+    }
+
+    @Nullable
+    @Override
+    public Action getAction(@AppAction int actionId) {
+        if (mActions.contains(actionId)) {
+            return mActions.get(actionId);
+        }
+
+        long ctp = 0, price = 0;
+        boolean exists = false;
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            Action a = mEnabledEconomicPolicies.valueAt(i).getAction(actionId);
+            if (a != null) {
+                exists = true;
+                ctp += a.costToProduce;
+                price += a.basePrice;
+            }
+        }
+        final Action action = exists ? new Action(actionId, ctp, price) : null;
+        mActions.put(actionId, action);
+        return action;
+    }
+
+    @Nullable
+    @Override
+    public Reward getReward(@UtilityReward int rewardId) {
+        if (mRewards.contains(rewardId)) {
+            return mRewards.get(rewardId);
+        }
+
+        long instantReward = 0, ongoingReward = 0, maxReward = 0;
+        boolean exists = false;
+        for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+            Reward r = mEnabledEconomicPolicies.valueAt(i).getReward(rewardId);
+            if (r != null) {
+                exists = true;
+                instantReward += r.instantReward;
+                ongoingReward += r.ongoingRewardPerSecond;
+                maxReward += r.maxDailyReward;
+            }
+        }
+        final Reward reward = exists
+                ? new Reward(rewardId, instantReward, ongoingReward, maxReward) : null;
+        mRewards.put(rewardId, reward);
+        return reward;
+    }
+
+    @Override
+    void dump(IndentingPrintWriter pw) {
+        dumpActiveModifiers(pw);
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
new file mode 100644
index 0000000..20b9c70
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.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.server.tare;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+
+/** Modifier that makes things more expensive in light and deep doze. */
+class DeviceIdleModifier extends Modifier {
+    private static final String TAG = "TARE-" + DeviceIdleModifier.class.getSimpleName();
+    private static final boolean DEBUG = InternalResourceService.DEBUG
+            || Log.isLoggable(TAG, Log.DEBUG);
+
+    private final InternalResourceService mIrs;
+    private final PowerManager mPowerManager;
+    private final DeviceIdleTracker mDeviceIdleTracker;
+
+    DeviceIdleModifier(@NonNull InternalResourceService irs) {
+        super();
+        mIrs = irs;
+        mPowerManager = irs.getContext().getSystemService(PowerManager.class);
+        mDeviceIdleTracker = new DeviceIdleTracker();
+        mDeviceIdleTracker.startTracking(irs.getContext());
+    }
+
+    @Override
+    long getModifiedCostToProduce(long ctp) {
+        if (mDeviceIdleTracker.mDeviceIdle) {
+            return (long) (1.2 * ctp);
+        }
+        if (mDeviceIdleTracker.mDeviceLightIdle) {
+            return (long) (1.1 * ctp);
+        }
+        return ctp;
+    }
+
+    @Override
+    void dump(IndentingPrintWriter pw) {
+        pw.print("idle=");
+        pw.println(mDeviceIdleTracker.mDeviceIdle);
+        pw.print("lightIdle=");
+        pw.println(mDeviceIdleTracker.mDeviceLightIdle);
+    }
+
+    private final class DeviceIdleTracker extends BroadcastReceiver {
+
+        private volatile boolean mDeviceIdle;
+        private volatile boolean mDeviceLightIdle;
+
+        DeviceIdleTracker() {
+        }
+
+        void startTracking(@NonNull Context context) {
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+            filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
+            context.registerReceiver(this, filter);
+
+            // Initialise tracker state.
+            mDeviceIdle = mPowerManager.isDeviceIdleMode();
+            mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+                if (mDeviceIdle != mPowerManager.isDeviceIdleMode()) {
+                    mDeviceIdle = mPowerManager.isDeviceIdleMode();
+                    mIrs.onDeviceStateChanged();
+                }
+            } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+                if (mDeviceIdle != mPowerManager.isLightDeviceIdleMode()) {
+                    mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
+                    mIrs.onDeviceStateChanged();
+                }
+            }
+        }
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
new file mode 100644
index 0000000..0e54163
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
+import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
+import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
+import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
+import static com.android.server.tare.Modifier.NUM_COST_MODIFIERS;
+
+import android.annotation.CallSuper;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.IndentingPrintWriter;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An EconomicPolicy includes pricing information and daily ARC requirements and suggestions.
+ * Policies are defined per participating system service. This allows each service’s EconomicPolicy
+ * to be isolated while allowing the core economic system to scale across policies to achieve a
+ * logical system-wide value system.
+ */
+public abstract class EconomicPolicy {
+    private static final String TAG = "TARE-" + EconomicPolicy.class.getSimpleName();
+
+    private static final int SHIFT_TYPE = 30;
+    static final int MASK_TYPE = 0b11 << SHIFT_TYPE;
+    static final int TYPE_REGULATION = 0 << SHIFT_TYPE;
+    static final int TYPE_ACTION = 1 << SHIFT_TYPE;
+    static final int TYPE_REWARD = 2 << SHIFT_TYPE;
+
+    private static final int SHIFT_POLICY = 29;
+    static final int MASK_POLICY = 0b1 << SHIFT_POLICY;
+    static final int POLICY_AM = 0 << SHIFT_POLICY;
+    static final int POLICY_JS = 1 << SHIFT_POLICY;
+
+    static final int MASK_EVENT = ~0 - (0b111 << SHIFT_POLICY);
+
+    static final int REGULATION_BASIC_INCOME = TYPE_REGULATION | 0;
+    static final int REGULATION_BIRTHRIGHT = TYPE_REGULATION | 1;
+    static final int REGULATION_TAX = TYPE_REGULATION | 2;
+
+    static final int REWARD_NOTIFICATION_SEEN = TYPE_REWARD | 0;
+    static final int REWARD_NOTIFICATION_INTERACTION = TYPE_REWARD | 1;
+    static final int REWARD_TOP_ACTIVITY = TYPE_REWARD | 2;
+    static final int REWARD_WIDGET_INTERACTION = TYPE_REWARD | 3;
+    static final int REWARD_OTHER_USER_INTERACTION = TYPE_REWARD | 4;
+
+    @IntDef({
+            AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT,
+            AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK,
+            JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START,
+            JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING,
+            JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START,
+            JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING,
+            JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START,
+            JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING,
+            JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START,
+            JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING,
+            JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START,
+            JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING,
+            JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AppAction {
+    }
+
+    @IntDef({
+            TYPE_ACTION,
+            TYPE_REGULATION,
+            TYPE_REWARD,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EventType {
+    }
+
+    @IntDef({
+            REWARD_TOP_ACTIVITY,
+            REWARD_NOTIFICATION_SEEN,
+            REWARD_NOTIFICATION_INTERACTION,
+            REWARD_WIDGET_INTERACTION,
+            REWARD_OTHER_USER_INTERACTION,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UtilityReward {
+    }
+
+    static class Action {
+        /** Unique id (including across policies) for this action. */
+        public final int id;
+        /**
+         * How many ARCs the system says it takes to perform this action.
+         */
+        public final long costToProduce;
+        /**
+         * The base price to perform this action. If this is
+         * less than the {@link #costToProduce}, then the system should not perform
+         * the action unless a modifier lowers the cost to produce.
+         */
+        public final long basePrice;
+
+        Action(int id, long costToProduce, long basePrice) {
+            this.id = id;
+            this.costToProduce = costToProduce;
+            this.basePrice = basePrice;
+        }
+    }
+
+    static class Reward {
+        /** Unique id (including across policies) for this reward. */
+        @UtilityReward
+        public final int id;
+        public final long instantReward;
+        /** Reward credited per second of ongoing activity. */
+        public final long ongoingRewardPerSecond;
+        /** The maximum amount an app can earn from this reward within a 24 hour period. */
+        public final long maxDailyReward;
+
+        Reward(int id, long instantReward, long ongoingReward, long maxDailyReward) {
+            this.id = id;
+            this.instantReward = instantReward;
+            this.ongoingRewardPerSecond = ongoingReward;
+            this.maxDailyReward = maxDailyReward;
+        }
+    }
+
+    private static final Modifier[] COST_MODIFIER_BY_INDEX = new Modifier[NUM_COST_MODIFIERS];
+
+    EconomicPolicy(@NonNull InternalResourceService irs) {
+        for (int mId : getCostModifiers()) {
+            initModifier(mId, irs);
+        }
+    }
+
+    @CallSuper
+    void onSystemServicesReady() {
+        for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
+            final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
+            if (modifier != null) {
+                modifier.onSystemServicesReady();
+            }
+        }
+    }
+
+    /**
+     * Returns the minimum suggested balance an app should have when the device is at 100% battery.
+     * This takes into account any exemptions the app may have.
+     */
+    abstract long getMinSatiatedBalance(int userId, @NonNull String pkgName);
+
+    /**
+     * Returns the maximum balance an app should have when the device is at 100% battery. This
+     * exists to ensure that no single app accumulate all available resources and increases fairness
+     * for all apps.
+     */
+    abstract long getMaxSatiatedBalance();
+
+    /**
+     * Returns the maximum number of narcs that should be in circulation at once when the device is
+     * at 100% battery.
+     */
+    abstract long getMaxSatiatedCirculation();
+
+    /** Return the set of modifiers that should apply to this policy's costs. */
+    @NonNull
+    abstract int[] getCostModifiers();
+
+    @Nullable
+    abstract Action getAction(@AppAction int actionId);
+
+    @Nullable
+    abstract Reward getReward(@UtilityReward int rewardId);
+
+    void dump(IndentingPrintWriter pw) {
+    }
+
+    final long getCostOfAction(int actionId, int userId, @NonNull String pkgName) {
+        final Action action = getAction(actionId);
+        if (action == null) {
+            return 0;
+        }
+        long ctp = action.costToProduce;
+        long price = action.basePrice;
+        final int[] costModifiers = getCostModifiers();
+        boolean useProcessStatePriceDeterminant = false;
+        for (int costModifier : costModifiers) {
+            if (costModifier == COST_MODIFIER_PROCESS_STATE) {
+                useProcessStatePriceDeterminant = true;
+            } else {
+                final Modifier modifier = getModifier(costModifier);
+                ctp = modifier.getModifiedCostToProduce(ctp);
+                price = modifier.getModifiedPrice(price);
+            }
+        }
+        // ProcessStateModifier needs to be done last.
+        if (useProcessStatePriceDeterminant) {
+            ProcessStateModifier processStateModifier =
+                    (ProcessStateModifier) getModifier(COST_MODIFIER_PROCESS_STATE);
+            price = processStateModifier.getModifiedPrice(userId, pkgName, ctp, price);
+        }
+        return price;
+    }
+
+    private static void initModifier(@Modifier.CostModifier final int modifierId,
+            @NonNull InternalResourceService irs) {
+        if (modifierId < 0 || modifierId >= COST_MODIFIER_BY_INDEX.length) {
+            throw new IllegalArgumentException("Invalid modifier id " + modifierId);
+        }
+        Modifier modifier = COST_MODIFIER_BY_INDEX[modifierId];
+        if (modifier == null) {
+            switch (modifierId) {
+                case COST_MODIFIER_CHARGING:
+                    modifier = new ChargingModifier(irs);
+                    break;
+                case COST_MODIFIER_DEVICE_IDLE:
+                    modifier = new DeviceIdleModifier(irs);
+                    break;
+                case COST_MODIFIER_POWER_SAVE_MODE:
+                    modifier = new PowerSaveModeModifier(irs);
+                    break;
+                case COST_MODIFIER_PROCESS_STATE:
+                    modifier = new ProcessStateModifier(irs);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid modifier id " + modifierId);
+            }
+            COST_MODIFIER_BY_INDEX[modifierId] = modifier;
+        }
+    }
+
+    @NonNull
+    private static Modifier getModifier(@Modifier.CostModifier final int modifierId) {
+        if (modifierId < 0 || modifierId >= COST_MODIFIER_BY_INDEX.length) {
+            throw new IllegalArgumentException("Invalid modifier id " + modifierId);
+        }
+        final Modifier modifier = COST_MODIFIER_BY_INDEX[modifierId];
+        if (modifier == null) {
+            throw new IllegalStateException(
+                    "Modifier #" + modifierId + " was never initialized");
+        }
+        return modifier;
+    }
+
+    @EventType
+    static int getEventType(int eventId) {
+        return eventId & MASK_TYPE;
+    }
+
+    @NonNull
+    static String eventToString(int eventId) {
+        switch (eventId & MASK_TYPE) {
+            case TYPE_ACTION:
+                return actionToString(eventId);
+
+            case TYPE_REGULATION:
+                return regulationToString(eventId);
+
+            case TYPE_REWARD:
+                return rewardToString(eventId);
+
+            default:
+                return "UNKNOWN_EVENT:" + Integer.toHexString(eventId);
+        }
+    }
+
+    @NonNull
+    static String actionToString(int eventId) {
+        switch (eventId & MASK_POLICY) {
+            case POLICY_AM:
+                switch (eventId) {
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE:
+                        return "ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT:
+                        return "ALARM_WAKEUP_EXACT";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE:
+                        return "ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT:
+                        return "ALARM_WAKEUP_INEXACT";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE:
+                        return "ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT:
+                        return "ALARM_NONWAKEUP_EXACT";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE:
+                        return "ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT:
+                        return "ALARM_NONWAKEUP_INEXACT";
+                    case AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK:
+                        return "ALARM_CLOCK";
+                }
+            case POLICY_JS:
+                switch (eventId) {
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START:
+                        return "JOB_MAX_START";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING:
+                        return "JOB_MAX_RUNNING";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START:
+                        return "JOB_HIGH_START";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING:
+                        return "JOB_HIGH_RUNNING";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START:
+                        return "JOB_DEFAULT_START";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING:
+                        return "JOB_DEFAULT_RUNNING";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START:
+                        return "JOB_LOW_START";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING:
+                        return "JOB_LOW_RUNNING";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START:
+                        return "JOB_MIN_START";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING:
+                        return "JOB_MIN_RUNNING";
+                    case JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT:
+                        return "JOB_TIMEOUT";
+                }
+        }
+        return "UNKNOWN_ACTION:" + Integer.toHexString(eventId);
+    }
+
+    @NonNull
+    static String regulationToString(int eventId) {
+        switch (eventId) {
+            case REGULATION_BASIC_INCOME:
+                return "BASIC_INCOME";
+            case REGULATION_BIRTHRIGHT:
+                return "BIRTHRIGHT";
+            case REGULATION_TAX:
+                return "TAX";
+        }
+        return "UNKNOWN_REGULATION:" + Integer.toHexString(eventId);
+    }
+
+    @NonNull
+    static String rewardToString(int eventId) {
+        switch (eventId) {
+            case REWARD_TOP_ACTIVITY:
+                return "REWARD_TOP_ACTIVITY";
+            case REWARD_NOTIFICATION_SEEN:
+                return "REWARD_NOTIFICATION_SEEN";
+            case REWARD_NOTIFICATION_INTERACTION:
+                return "REWARD_NOTIFICATION_INTERACTION";
+            case REWARD_WIDGET_INTERACTION:
+                return "REWARD_WIDGET_INTERACTION";
+            case REWARD_OTHER_USER_INTERACTION:
+                return "REWARD_OTHER_USER_INTERACTION";
+        }
+        return "UNKNOWN_REWARD:" + Integer.toHexString(eventId);
+    }
+
+    protected static void dumpActiveModifiers(IndentingPrintWriter pw) {
+        for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
+            pw.print("Modifier ");
+            pw.println(i);
+            pw.increaseIndent();
+
+            Modifier modifier = COST_MODIFIER_BY_INDEX[i];
+            if (modifier != null) {
+                modifier.dump(pw);
+            } else {
+                pw.println("NOT ACTIVE");
+            }
+
+            pw.decreaseIndent();
+        }
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
new file mode 100644
index 0000000..5edeeed
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Interface for the system server to deal with the resource economy subsystem.
+ *
+ * @hide
+ */
+interface EconomyManagerInternal {
+    /** Listener for when an app changes its solvency status. */
+    interface BalanceChangeListener {
+        /**
+         * Called when an app runs out of funds.
+         * {@link #noteOngoingEventStopped(int, String, int, String)} must still be called to
+         * formally end the action.
+         */
+        void onBankruptcy(int userId, @NonNull String pkgName);
+
+        /**
+         * Called when an app goes from being insolvent to solvent.
+         */
+        void onSolvent(int userId, @NonNull String pkgName);
+    }
+
+    /** Register a {@link BalanceChangeListener} to track all apps' solvency status changes. */
+    void registerBalanceChangeListener(@NonNull BalanceChangeListener listener);
+
+    /**
+     * Unregister a {@link BalanceChangeListener} from being notified of any app's solvency status
+     * changes.
+     */
+    void unregisterBalanceChangeListener(@NonNull BalanceChangeListener listener);
+
+    /**
+     * Return {@code true} if the app has a balance equal to or greater than the specified min
+     * balance.
+     */
+    boolean hasBalanceAtLeast(int userId, @NonNull String pkgName, int minBalance);
+
+    /**
+     * Note that an instantaneous event has occurred. The event must be specified in one of the
+     * EconomicPolicies.
+     *
+     * @param tag An optional tag that can be used to differentiate the same event for the same app.
+     */
+    void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
+            @Nullable String tag);
+
+    /**
+     * Note that a long-running event is starting. The event must be specified in one of the
+     * EconomicPolicies. You must always call
+     * {@link #noteOngoingEventStopped(int, String, int, String)} to end the event. Ongoing
+     * events will be separated and grouped by event-tag combinations. There must be an equal
+     * number of start() and stop() calls for the same event-tag combination in order for the
+     * tracking to finally stop (ie. ongoing events are ref-counted).
+     *
+     * @param tag An optional tag that can be used to differentiate the same event for the same app.
+     */
+    void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
+            @Nullable String tag);
+
+    /**
+     * Note that a long-running event has stopped. The event must be specified in one of the
+     * EconomicPolicies. Ongoing events are separated and grouped by event-tag combinations.
+     * There must be an equal number of start() and stop() calls for the same event-tag combination
+     * in order for the tracking to finally stop (ie. ongoing events are ref-counted).
+     *
+     * @param tag An optional tag that can be used to differentiate the same event for the same app.
+     */
+    void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
+            @Nullable String tag);
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
new file mode 100644
index 0000000..3ccf263
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.BatteryManagerInternal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseSetArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.tare.EconomyManagerInternal.BalanceChangeListener;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * Responsible for handling app's ARC count based on events, ensuring ARCs are credited when
+ * appropriate, and reclaiming ARCs at the right times. The IRS deals with the high level details
+ * while the {@link Agent} deals with the nitty-gritty details.
+ *
+ * Note on locking: Any function with the suffix 'Locked' needs to lock on {@link #mLock}.
+ *
+ * @hide
+ */
+public class InternalResourceService extends SystemService {
+    public static final String TAG = "TARE-IRS";
+    public static final boolean DEBUG = Log.isLoggable("TARE", Log.DEBUG);
+
+    /** Global local for all resource economy state. */
+    private final Object mLock = new Object();
+
+    private final Handler mHandler;
+    private final BatteryManagerInternal mBatteryManagerInternal;
+    private final PackageManager mPackageManager;
+
+    private final CompleteEconomicPolicy mCompleteEconomicPolicy;
+    private final Agent mAgent;
+
+    private final CopyOnWriteArraySet<BalanceChangeListener> mBalanceChangeListeners =
+            new CopyOnWriteArraySet<>();
+
+    @NonNull
+    @GuardedBy("mLock")
+    private List<PackageInfo> mPkgCache = new ArrayList<>();
+
+    /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
+    @GuardedBy("mLock")
+    private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
+
+    @GuardedBy("mLock")
+    private boolean mIsSetup;
+    // In the range [0,100] to represent 0% to 100% battery.
+    @GuardedBy("mLock")
+    private int mCurrentBatteryLevel;
+
+    @SuppressWarnings("FieldCanBeLocal")
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Nullable
+        private String getPackageName(Intent intent) {
+            Uri uri = intent.getData();
+            return uri != null ? uri.getSchemeSpecificPart() : null;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case Intent.ACTION_BATTERY_LEVEL_CHANGED:
+                    onBatteryLevelChanged();
+                    break;
+                case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
+                    final String pkgName = getPackageName(intent);
+                    final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    onPackageRemoved(pkgUid, pkgName);
+                }
+                break;
+                case Intent.ACTION_PACKAGE_ADDED: {
+                    if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                        final String pkgName = getPackageName(intent);
+                        final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                        onPackageAdded(pkgUid, pkgName);
+                    }
+                }
+                break;
+                case Intent.ACTION_PACKAGE_RESTARTED: {
+                    final String pkgName = getPackageName(intent);
+                    final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    final int userId = UserHandle.getUserId(pkgUid);
+                    onPackageForceStopped(userId, pkgName);
+                }
+                break;
+                case Intent.ACTION_USER_ADDED: {
+                    final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                    onUserAdded(userId);
+                }
+                break;
+                case Intent.ACTION_USER_REMOVED: {
+                    final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                    onUserRemoved(userId);
+                }
+                break;
+            }
+        }
+    };
+
+    private static final int MSG_NOTIFY_BALANCE_CHANGE_LISTENERS = 0;
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public InternalResourceService(Context context) {
+        super(context);
+
+        mHandler = new IrsHandler(TareHandlerThread.get().getLooper());
+        mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
+        mPackageManager = context.getPackageManager();
+        mCompleteEconomicPolicy = new CompleteEconomicPolicy(this);
+        mAgent = new Agent(this, mCompleteEconomicPolicy);
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
+        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+        final IntentFilter pkgFilter = new IntentFilter();
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+        pkgFilter.addDataScheme("package");
+        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
+        final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_ADDED);
+        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+
+        publishLocalService(EconomyManagerInternal.class, new LocalService());
+    }
+
+    @Override
+    public void onStart() {
+
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (PHASE_SYSTEM_SERVICES_READY == phase) {
+            synchronized (mLock) {
+                mCurrentBatteryLevel = getCurrentBatteryLevel();
+                // TODO: base on if we have anything persisted
+                final boolean isFirstSetup = true;
+                if (isFirstSetup) {
+                    mHandler.post(this::setupEconomy);
+                } else {
+                    mIsSetup = true;
+                }
+            }
+        }
+    }
+
+    @NonNull
+    Object getLock() {
+        return mLock;
+    }
+
+    @NonNull
+    List<PackageInfo> getInstalledPackages() {
+        synchronized (mLock) {
+            return mPkgCache;
+        }
+    }
+
+    @GuardedBy("mLock")
+    long getMaxCirculationLocked() {
+        return mCurrentBatteryLevel * mCompleteEconomicPolicy.getMaxSatiatedCirculation() / 100;
+    }
+
+    @GuardedBy("mLock")
+    long getMinBalanceLocked(final int userId, @NonNull final String pkgName) {
+        return mCurrentBatteryLevel * mCompleteEconomicPolicy.getMinSatiatedBalance(userId, pkgName)
+                / 100;
+    }
+
+    @Nullable
+    @GuardedBy("mLock")
+    ArraySet<String> getPackagesForUidLocked(final int uid) {
+        ArraySet<String> packages = mUidToPackageCache.get(uid);
+        if (packages == null) {
+            final String[] pkgs = mPackageManager.getPackagesForUid(uid);
+            if (pkgs != null) {
+                for (String pkg : pkgs) {
+                    mUidToPackageCache.add(uid, pkg);
+                }
+                packages = mUidToPackageCache.get(uid);
+            }
+        }
+        return packages;
+    }
+
+    void onBatteryLevelChanged() {
+        synchronized (mLock) {
+            final int newBatteryLevel = getCurrentBatteryLevel();
+            if (newBatteryLevel > mCurrentBatteryLevel) {
+                mAgent.distributeBasicIncomeLocked(newBatteryLevel);
+            }
+            mCurrentBatteryLevel = newBatteryLevel;
+        }
+    }
+
+    void onDeviceStateChanged() {
+    }
+
+    void onPackageAdded(final int uid, @NonNull final String pkgName) {
+        final int userId = UserHandle.getUserId(uid);
+        final PackageInfo packageInfo;
+        try {
+            packageInfo = mPackageManager.getPackageInfoAsUser(pkgName, 0, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName);
+            return;
+        }
+        synchronized (mLock) {
+            mPkgCache.add(packageInfo);
+            mUidToPackageCache.add(uid, pkgName);
+            // TODO: only do this when the user first launches the app (app leaves stopped state)
+            mAgent.grantBirthrightLocked(userId, pkgName);
+        }
+    }
+
+    void onPackageForceStopped(final int userId, @NonNull final String pkgName) {
+        synchronized (mLock) {
+            // TODO: reduce ARC count by some amount
+        }
+    }
+
+    void onPackageRemoved(final int uid, @NonNull final String pkgName) {
+        final int userId = UserHandle.getUserId(uid);
+        synchronized (mLock) {
+            mUidToPackageCache.remove(uid, pkgName);
+            for (int i = 0; i < mPkgCache.size(); ++i) {
+                PackageInfo pkgInfo = mPkgCache.get(i);
+                if (UserHandle.getUserId(pkgInfo.applicationInfo.uid) == userId
+                        && pkgName.equals(pkgInfo.packageName)) {
+                    mPkgCache.remove(i);
+                    break;
+                }
+            }
+            mAgent.onPackageRemovedLocked(userId, pkgName);
+        }
+    }
+
+    void onUidStateChanged(final int uid) {
+    }
+
+    void onUserAdded(final int userId) {
+        synchronized (mLock) {
+            loadInstalledPackageListLocked();
+            mAgent.grantBirthrightsLocked(userId);
+        }
+    }
+
+    void onUserRemoved(final int userId) {
+        synchronized (mLock) {
+            ArrayList<String> removedPkgs = new ArrayList<>();
+            for (int i = mPkgCache.size() - 1; i >= 0; --i) {
+                PackageInfo pkgInfo = mPkgCache.get(i);
+                if (UserHandle.getUserId(pkgInfo.applicationInfo.uid) == userId) {
+                    removedPkgs.add(pkgInfo.packageName);
+                    mUidToPackageCache.remove(pkgInfo.applicationInfo.uid);
+                    mPkgCache.remove(i);
+                    break;
+                }
+            }
+            loadInstalledPackageListLocked();
+            mAgent.onUserRemovedLocked(userId, removedPkgs);
+        }
+    }
+
+    void postSolvencyChanged(final int userId, @NonNull final String pkgName, boolean nowSolvent) {
+        mHandler.obtainMessage(
+                MSG_NOTIFY_BALANCE_CHANGE_LISTENERS, userId, nowSolvent ? 1 : 0, pkgName)
+                .sendToTarget();
+    }
+
+    private int getCurrentBatteryLevel() {
+        return mBatteryManagerInternal.getBatteryLevel();
+    }
+
+    @GuardedBy("mLock")
+    private void loadInstalledPackageListLocked() {
+        mPkgCache = mPackageManager.getInstalledPackages(0);
+    }
+
+    private void setupEconomy() {
+        synchronized (mLock) {
+            loadInstalledPackageListLocked();
+            mAgent.grantBirthrightsLocked();
+            mIsSetup = true;
+        }
+    }
+
+    private final class IrsHandler extends Handler {
+        IrsHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_NOTIFY_BALANCE_CHANGE_LISTENERS:
+                    final int userId = msg.arg1;
+                    final String pkgName = (String) msg.obj;
+                    final boolean nowSolvent = msg.arg2 == 1;
+                    for (BalanceChangeListener listener : mBalanceChangeListeners) {
+                        if (nowSolvent) {
+                            listener.onSolvent(userId, pkgName);
+                        } else {
+                            listener.onBankruptcy(userId, pkgName);
+                        }
+                    }
+                    break;
+            }
+        }
+    }
+
+    // TODO: implement
+    private final class LocalService implements EconomyManagerInternal {
+
+        @Override
+        public void registerBalanceChangeListener(@NonNull BalanceChangeListener listener) {
+            mBalanceChangeListeners.add(listener);
+        }
+
+        @Override
+        public void unregisterBalanceChangeListener(@NonNull BalanceChangeListener listener) {
+            mBalanceChangeListeners.remove(listener);
+        }
+
+        @Override
+        public boolean hasBalanceAtLeast(int userId, @NonNull String pkgName, int minBalance) {
+            return false;
+        }
+
+        @Override
+        public void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
+                @Nullable String tag) {
+            synchronized (mLock) {
+                mAgent.noteInstantaneousEventLocked(userId, pkgName, eventId, tag);
+            }
+        }
+
+        @Override
+        public void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
+                @Nullable String tag) {
+        }
+
+        @Override
+        public void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
+                @Nullable String tag) {
+        }
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
new file mode 100644
index 0000000..cce75f7
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.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 com.android.server.tare;
+
+import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
+import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
+import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
+import static com.android.server.tare.TareUtils.arcToNarc;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.SparseArray;
+
+/**
+ * Policy defining pricing information and daily ARC requirements and suggestions for
+ * JobScheduler.
+ */
+public class JobSchedulerEconomicPolicy extends EconomicPolicy {
+    public static final int ACTION_JOB_MAX_START = TYPE_ACTION | POLICY_JS | 0;
+    public static final int ACTION_JOB_MAX_RUNNING = TYPE_ACTION | POLICY_JS | 1;
+    public static final int ACTION_JOB_HIGH_START = TYPE_ACTION | POLICY_JS | 2;
+    public static final int ACTION_JOB_HIGH_RUNNING = TYPE_ACTION | POLICY_JS | 3;
+    public static final int ACTION_JOB_DEFAULT_START = TYPE_ACTION | POLICY_JS | 4;
+    public static final int ACTION_JOB_DEFAULT_RUNNING = TYPE_ACTION | POLICY_JS | 5;
+    public static final int ACTION_JOB_LOW_START = TYPE_ACTION | POLICY_JS | 6;
+    public static final int ACTION_JOB_LOW_RUNNING = TYPE_ACTION | POLICY_JS | 7;
+    public static final int ACTION_JOB_MIN_START = TYPE_ACTION | POLICY_JS | 8;
+    public static final int ACTION_JOB_MIN_RUNNING = TYPE_ACTION | POLICY_JS | 9;
+    public static final int ACTION_JOB_TIMEOUT = TYPE_ACTION | POLICY_JS | 10;
+
+    private static final int[] COST_MODIFIERS = new int[]{
+            COST_MODIFIER_CHARGING,
+            COST_MODIFIER_POWER_SAVE_MODE,
+            COST_MODIFIER_PROCESS_STATE
+    };
+
+    private final SparseArray<Action> mActions = new SparseArray<>();
+    private final SparseArray<Reward> mRewards = new SparseArray<>();
+
+    JobSchedulerEconomicPolicy(InternalResourceService irs) {
+        super(irs);
+        loadActions();
+        loadRewards();
+    }
+
+    @Override
+    long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
+        // TODO: incorporate time since usage
+        return arcToNarc(2000);
+    }
+
+    @Override
+    long getMaxSatiatedBalance() {
+        return arcToNarc(60000);
+    }
+
+    @Override
+    long getMaxSatiatedCirculation() {
+        return arcToNarc(691200);
+    }
+
+    @NonNull
+    @Override
+    int[] getCostModifiers() {
+        return COST_MODIFIERS;
+    }
+
+    @Nullable
+    @Override
+    Action getAction(@AppAction int actionId) {
+        return mActions.get(actionId);
+    }
+
+    @Nullable
+    @Override
+    Reward getReward(@UtilityReward int rewardId) {
+        return mRewards.get(rewardId);
+    }
+
+    private void loadActions() {
+        mActions.put(ACTION_JOB_MAX_START,
+                new Action(ACTION_JOB_MAX_START, arcToNarc(3), arcToNarc(10)));
+        mActions.put(ACTION_JOB_MAX_RUNNING,
+                new Action(ACTION_JOB_MAX_RUNNING, arcToNarc(2), arcToNarc(5)));
+        mActions.put(ACTION_JOB_HIGH_START,
+                new Action(ACTION_JOB_HIGH_START, arcToNarc(3), arcToNarc(8)));
+        mActions.put(ACTION_JOB_HIGH_RUNNING,
+                new Action(ACTION_JOB_HIGH_RUNNING, arcToNarc(2), arcToNarc(4)));
+        mActions.put(ACTION_JOB_DEFAULT_START,
+                new Action(ACTION_JOB_DEFAULT_START, arcToNarc(3), arcToNarc(6)));
+        mActions.put(ACTION_JOB_DEFAULT_RUNNING,
+                new Action(ACTION_JOB_DEFAULT_RUNNING, arcToNarc(2), arcToNarc(3)));
+        mActions.put(ACTION_JOB_LOW_START,
+                new Action(ACTION_JOB_LOW_START, arcToNarc(3), arcToNarc(4)));
+        mActions.put(ACTION_JOB_LOW_RUNNING,
+                new Action(ACTION_JOB_LOW_RUNNING, arcToNarc(2), arcToNarc(2)));
+        mActions.put(ACTION_JOB_MIN_START,
+                new Action(ACTION_JOB_MIN_START, arcToNarc(3), arcToNarc(2)));
+        mActions.put(ACTION_JOB_MIN_RUNNING,
+                new Action(ACTION_JOB_MIN_RUNNING, arcToNarc(2), arcToNarc(1)));
+        mActions.put(ACTION_JOB_TIMEOUT,
+                new Action(ACTION_JOB_TIMEOUT, arcToNarc(30), arcToNarc(60)));
+    }
+
+    private void loadRewards() {
+        mRewards.put(REWARD_TOP_ACTIVITY,
+                new Reward(REWARD_TOP_ACTIVITY,
+                        arcToNarc(0), /* .5 arcs */ arcToNarc(5) / 10, arcToNarc(15000)));
+        mRewards.put(REWARD_NOTIFICATION_SEEN,
+                new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(1), arcToNarc(0), arcToNarc(10)));
+        mRewards.put(REWARD_NOTIFICATION_INTERACTION,
+                new Reward(REWARD_NOTIFICATION_INTERACTION,
+                        arcToNarc(5), arcToNarc(0), arcToNarc(5000)));
+        mRewards.put(REWARD_WIDGET_INTERACTION,
+                new Reward(REWARD_WIDGET_INTERACTION,
+                        arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+        mRewards.put(REWARD_OTHER_USER_INTERACTION,
+                new Reward(REWARD_OTHER_USER_INTERACTION,
+                        arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
new file mode 100644
index 0000000..ae1bf26
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
@@ -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.server.tare;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+
+import static com.android.server.tare.TareUtils.dumpTime;
+import static com.android.server.tare.TareUtils.narcToString;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.IndentingPrintWriter;
+import android.util.SparseLongArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Ledger to track the last recorded balance and recent activities of an app.
+ */
+class Ledger {
+    static class Transaction {
+        public final long startTimeMs;
+        public final long endTimeMs;
+        public final int eventId;
+        @Nullable
+        public final String tag;
+        public final long delta;
+
+        Transaction(long startTimeMs, long endTimeMs,
+                int eventId, @Nullable String tag, long delta) {
+            this.startTimeMs = startTimeMs;
+            this.endTimeMs = endTimeMs;
+            this.eventId = eventId;
+            this.tag = tag;
+            this.delta = delta;
+        }
+    }
+
+    /** Last saved balance. This doesn't take currently ongoing events into account. */
+    private long mCurrentBalance = 0;
+    private final List<Transaction> mTransactions = new ArrayList<>();
+    private final SparseLongArray mCumulativeDeltaPerReason = new SparseLongArray();
+    private long mEarliestSumTime;
+
+    Ledger() {
+    }
+
+    long getCurrentBalance() {
+        return mCurrentBalance;
+    }
+
+    @Nullable
+    Transaction getEarliestTransaction() {
+        if (mTransactions.size() > 0) {
+            return mTransactions.get(0);
+        }
+        return null;
+    }
+
+    void recordTransaction(@NonNull Transaction transaction) {
+        mTransactions.add(transaction);
+        mCurrentBalance += transaction.delta;
+
+        final long sum = mCumulativeDeltaPerReason.get(transaction.eventId);
+        mCumulativeDeltaPerReason.put(transaction.eventId, sum + transaction.delta);
+        mEarliestSumTime = Math.min(mEarliestSumTime, transaction.startTimeMs);
+    }
+
+    long get24HourSum(int eventId, final long now) {
+        final long windowStartTime = now - 24 * HOUR_IN_MILLIS;
+        if (mEarliestSumTime < windowStartTime) {
+            // Need to redo sums
+            mCumulativeDeltaPerReason.clear();
+            for (int i = mTransactions.size() - 1; i >= 0; --i) {
+                final Transaction transaction = mTransactions.get(i);
+                if (transaction.endTimeMs <= windowStartTime) {
+                    break;
+                }
+                long sum = mCumulativeDeltaPerReason.get(transaction.eventId);
+                if (transaction.startTimeMs >= windowStartTime) {
+                    sum += transaction.delta;
+                } else {
+                    // Pro-rate durationed deltas. Intentionally floor the result.
+                    sum += (long) (1.0 * (transaction.endTimeMs - windowStartTime)
+                            * transaction.delta)
+                            / (transaction.endTimeMs - transaction.startTimeMs);
+                }
+                mCumulativeDeltaPerReason.put(transaction.eventId, sum);
+            }
+            mEarliestSumTime = windowStartTime;
+        }
+        return mCumulativeDeltaPerReason.get(eventId);
+    }
+
+    /** Deletes transactions that are older than {@code minAgeMs}. */
+    void removeOldTransactions(long minAgeMs) {
+        final long cutoff = System.currentTimeMillis() - minAgeMs;
+        while (mTransactions.get(0).endTimeMs <= cutoff) {
+            mTransactions.remove(0);
+        }
+    }
+
+    void dump(IndentingPrintWriter pw) {
+        pw.print("Current balance", narcToString(getCurrentBalance())).println();
+        mTransactions.forEach((transaction) -> {
+            dumpTime(pw, transaction.startTimeMs);
+            pw.print("--");
+            dumpTime(pw, transaction.endTimeMs);
+            pw.print(": ");
+            pw.print(EconomicPolicy.eventToString(transaction.eventId));
+            pw.print(" --> ");
+            pw.println(narcToString(transaction.delta));
+        });
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
new file mode 100644
index 0000000..6b89b79
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.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.server.tare;
+
+import android.annotation.IntDef;
+import android.util.IndentingPrintWriter;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base class of a modifier that can affect end pricing.
+ */
+abstract class Modifier {
+    static final int COST_MODIFIER_CHARGING = 0;
+    static final int COST_MODIFIER_DEVICE_IDLE = 1;
+    static final int COST_MODIFIER_POWER_SAVE_MODE = 2;
+    static final int COST_MODIFIER_PROCESS_STATE = 3;
+    static final int NUM_COST_MODIFIERS = COST_MODIFIER_PROCESS_STATE + 1;
+
+    @IntDef({
+            COST_MODIFIER_CHARGING,
+            COST_MODIFIER_DEVICE_IDLE,
+            COST_MODIFIER_POWER_SAVE_MODE,
+            COST_MODIFIER_PROCESS_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CostModifier {
+    }
+
+    /**
+     * Returns a modified cost to produce based on the modifier's state.
+     *
+     * @param ctp Current cost to produce
+     */
+    long getModifiedCostToProduce(long ctp) {
+        return ctp;
+    }
+
+    /**
+     * Returns a modified price based on the modifier's state.
+     *
+     * @param price Current price
+     */
+    long getModifiedPrice(long price) {
+        return price;
+    }
+
+    void onSystemServicesReady() {
+    }
+
+    abstract void dump(IndentingPrintWriter pw);
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/OWNERS b/apex/jobscheduler/service/java/com/android/server/tare/OWNERS
new file mode 100644
index 0000000..96ec75f
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/OWNERS
@@ -0,0 +1,5 @@
+dplotnikov@google.com
+kwekua@google.com
+mwachens@google.com
+suprabh@google.com
+yamasani@google.com
\ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
new file mode 100644
index 0000000..764a3a8
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.NonNull;
+import android.os.PowerManager;
+import android.util.IndentingPrintWriter;
+
+/** Modifier that makes things more expensive in adaptive and full battery saver are active. */
+class PowerSaveModeModifier extends Modifier {
+    private final InternalResourceService mIrs;
+    private final PowerManager mPowerManager;
+
+    PowerSaveModeModifier(@NonNull InternalResourceService irs) {
+        super();
+        mIrs = irs;
+        mPowerManager = irs.getContext().getSystemService(PowerManager.class);
+    }
+
+    @Override
+    long getModifiedCostToProduce(long ctp) {
+        if (mPowerManager.isPowerSaveMode()) {
+            return (long) (1.5 * ctp);
+        }
+        // TODO: get adaptive power save mode
+        if (mPowerManager.isPowerSaveMode()) {
+            return (long) (1.25 * ctp);
+        }
+        return ctp;
+    }
+
+    @Override
+    void dump(IndentingPrintWriter pw) {
+        pw.print("power save=");
+        pw.println(mPowerManager.isPowerSaveMode());
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
new file mode 100644
index 0000000..2ee6459
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.IUidObserver;
+import android.content.pm.PackageManagerInternal;
+import android.os.RemoteException;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
+import android.util.SparseArrayMap;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Modifier that makes things more cheaper based on an app's process state. */
+class ProcessStateModifier extends Modifier {
+    private static final String TAG = "TARE-" + ProcessStateModifier.class.getSimpleName();
+
+    private static final int PROC_STATE_BUCKET_NONE = 0;
+    private static final int PROC_STATE_BUCKET_TOP = 1;
+    private static final int PROC_STATE_BUCKET_FGS = 2;
+    private static final int PROC_STATE_BUCKET_BFGS = 3;
+    private static final int PROC_STATE_BUCKET_BG = 4;
+
+    @IntDef(prefix = {"PROC_STATE_BUCKET_"}, value = {
+            PROC_STATE_BUCKET_NONE,
+            PROC_STATE_BUCKET_TOP,
+            PROC_STATE_BUCKET_FGS,
+            PROC_STATE_BUCKET_BFGS,
+            PROC_STATE_BUCKET_BG
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProcStateBucket {
+    }
+
+    private final Object mLock = new Object();
+    private final InternalResourceService mIrs;
+    private final PackageManagerInternal mPackageManagerInternal;
+
+    /** Cached mapping of userId+package to their UIDs (for all users) */
+    private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
+
+    @GuardedBy("mLock")
+    private final SparseIntArray mUidProcStateBucketCache = new SparseIntArray();
+
+    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+        @Override
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
+            final int newBucket = getProcStateBucket(procState);
+            synchronized (mLock) {
+                final int curBucket = mUidProcStateBucketCache.get(uid);
+                if (curBucket != newBucket) {
+                    mUidProcStateBucketCache.put(uid, newBucket);
+                }
+                notifyStateChangedLocked(uid);
+            }
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) {
+            synchronized (mLock) {
+                if (mUidProcStateBucketCache.indexOfKey(uid) < 0) {
+                    Slog.e(TAG, "UID " + uid + " marked gone but wasn't in cache.");
+                    return;
+                }
+                mUidProcStateBucketCache.delete(uid);
+                notifyStateChangedLocked(uid);
+            }
+        }
+
+        @Override
+        public void onUidActive(int uid) {
+        }
+
+        @Override
+        public void onUidIdle(int uid, boolean disabled) {
+        }
+
+        @Override
+        public void onUidCachedChanged(int uid, boolean cached) {
+        }
+    };
+
+    ProcessStateModifier(@NonNull InternalResourceService irs) {
+        super();
+        mIrs = irs;
+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+    }
+
+    @Override
+    @GuardedBy("mLock")
+    void onSystemServicesReady() {
+        try {
+            ActivityManager.getService().registerUidObserver(mUidObserver,
+                    ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
+                    ActivityManager.PROCESS_STATE_UNKNOWN, null);
+        } catch (RemoteException e) {
+            // ignored; both services live in system_server
+        }
+    }
+
+    /**
+     * Get the final modified price based on an app's process state.
+     *
+     * @param ctp   Cost to produce. @see EconomicPolicy.Action#costToProduce
+     * @param price Current price
+     */
+    long getModifiedPrice(final int userId, @NonNull final String pkgName,
+            final long ctp, final long price) {
+        final int procState;
+        synchronized (mLock) {
+            procState = mUidProcStateBucketCache.get(
+                    getUidLocked(userId, pkgName), PROC_STATE_BUCKET_NONE);
+        }
+        switch (procState) {
+            case PROC_STATE_BUCKET_TOP:
+                return 0;
+            case PROC_STATE_BUCKET_FGS:
+                // Can't get notification priority. Just use CTP for now.
+                return ctp;
+            case PROC_STATE_BUCKET_BFGS:
+                return (long) (ctp + .5 * (price - ctp));
+            case PROC_STATE_BUCKET_BG:
+            default:
+                return price;
+        }
+    }
+
+    @Override
+    @GuardedBy("mLock")
+    void dump(IndentingPrintWriter pw) {
+        pw.print("Proc state bucket cache = ");
+        pw.println(mUidProcStateBucketCache);
+    }
+
+    @GuardedBy("mLock")
+    private int getUidLocked(final int userId, @NonNull final String pkgName) {
+        if (!mPackageToUidCache.contains(userId, pkgName)) {
+            mPackageToUidCache.add(userId, pkgName,
+                    mPackageManagerInternal.getPackageUid(pkgName, 0, userId));
+        }
+        return mPackageToUidCache.get(userId, pkgName);
+    }
+
+    @ProcStateBucket
+    private int getProcStateBucket(int procState) {
+        if (procState <= ActivityManager.PROCESS_STATE_TOP) {
+            return PROC_STATE_BUCKET_TOP;
+        }
+        if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+            return PROC_STATE_BUCKET_FGS;
+        }
+        if (procState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+            return PROC_STATE_BUCKET_BFGS;
+        }
+        return PROC_STATE_BUCKET_BG;
+    }
+
+    @GuardedBy("mLock")
+    private void notifyStateChangedLocked(final int uid) {
+        // Never call out to the IRS with the local lock held.
+        TareHandlerThread.getHandler().post(() -> mIrs.onUidStateChanged(uid));
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
new file mode 100644
index 0000000..73b00b6
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
@@ -0,0 +1,34 @@
+{
+    "presubmit": [
+        {
+            "name": "FrameworksMockingServicesTests",
+            "options": [
+                {"include-filter": "com.android.server.tare"},
+                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+                {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+            ]
+        },
+        {
+            "name": "FrameworksServicesTests",
+            "options": [
+                {"include-filter": "com.android.server.tare"},
+                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+                {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+            ]
+        }
+    ],
+    "postsubmit": [
+        {
+            "name": "FrameworksMockingServicesTests",
+            "options": [
+                {"include-filter": "com.android.server.tare"}
+            ]
+        },
+        {
+            "name": "FrameworksServicesTests",
+            "options": [
+                {"include-filter": "com.android.server.tare"}
+            ]
+        }
+    ]
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java b/apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java
new file mode 100644
index 0000000..5b2b660
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Trace;
+
+/**
+ * Singleton thread for all of TARE.
+ *
+ * @see com.android.internal.os.BackgroundThread
+ */
+final class TareHandlerThread extends HandlerThread {
+
+    private static TareHandlerThread sInstance;
+    private static Handler sHandler;
+
+    private TareHandlerThread() {
+        super("tare");
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new TareHandlerThread();
+            sInstance.start();
+            final Looper looper = sInstance.getLooper();
+            looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    static TareHandlerThread get() {
+        synchronized (TareHandlerThread.class) {
+            ensureThreadLocked();
+        }
+        return sInstance;
+    }
+
+    /** Returns the singleton handler for TareHandlerThread. */
+    public static Handler getHandler() {
+        synchronized (TareHandlerThread.class) {
+            ensureThreadLocked();
+        }
+        return sHandler;
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
new file mode 100644
index 0000000..2d72f56
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.util.IndentingPrintWriter;
+
+import java.text.SimpleDateFormat;
+
+class TareUtils {
+    private static final long NARC_IN_ARC = 1_000_000_000L;
+
+    @SuppressLint("SimpleDateFormat")
+    private static final SimpleDateFormat sDumpDateFormat =
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+    static long arcToNarc(int arcs) {
+        return arcs * NARC_IN_ARC;
+    }
+
+    static void dumpTime(IndentingPrintWriter pw, long time) {
+        pw.print(sDumpDateFormat.format(time));
+    }
+
+    static int narcToArc(long narcs) {
+        return (int) (narcs / NARC_IN_ARC);
+    }
+
+    @NonNull
+    static String narcToString(long narcs) {
+        if (narcs == 0) {
+            return "0 ARCs";
+        }
+        final long sub = Math.abs(narcs) % NARC_IN_ARC;
+        final long arcs = narcToArc(narcs);
+        if (arcs == 0) {
+            return sub + " narcs";
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append(arcs);
+        if (sub > 0) {
+            sb.append(".").append(sub / (NARC_IN_ARC / 1000));
+        }
+        sb.append(" ARCs");
+        return sb.toString();
+    }
+}
diff --git a/apex/media/framework/TEST_MAPPING b/apex/media/framework/TEST_MAPPING
index 70c9087..3d21914 100644
--- a/apex/media/framework/TEST_MAPPING
+++ b/apex/media/framework/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "CtsMediaParserTestCases"
     },
     {
-      "name": "CtsMediaParserHostSideTestCases"
+      "name": "CtsMediaParserHostTestCases"
     }
   ]
 }
diff --git a/boot/Android.bp b/boot/Android.bp
index e8d88a5..b71f9bf 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -76,6 +76,10 @@
             module: "com.android.mediaprovider-bootclasspath-fragment",
         },
         {
+            apex: "com.android.nearby",
+            module: "com.android.nearby-bootclasspath-fragment",
+        },
+        {
             apex: "com.android.os.statsd",
             module: "com.android.os.statsd-bootclasspath-fragment",
         },
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index d4da5e5..7e6a521 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -45,13 +45,13 @@
 #define COLORSPACE_SRGB       1
 #define COLORSPACE_DISPLAY_P3 2
 
-static void usage(const char* pname, PhysicalDisplayId displayId)
+static void usage(const char* pname, DisplayId displayId)
 {
     fprintf(stderr,
             "usage: %s [-hp] [-d display-id] [FILENAME]\n"
             "   -h: this message\n"
             "   -p: save the file as a png.\n"
-            "   -d: specify the physical display ID to capture (default: %s)\n"
+            "   -d: specify the display ID to capture (default: %s)\n"
             "       see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
             "If FILENAME ends with .png it will be saved as a png.\n"
             "If FILENAME is not given, the results will be printed to stdout.\n",
@@ -121,9 +121,9 @@
 
 int main(int argc, char** argv)
 {
-    std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
+    std::optional<DisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
     if (!displayId) {
-        fprintf(stderr, "Failed to get token for internal display\n");
+        fprintf(stderr, "Failed to get ID for internal display\n");
         return 1;
     }
 
@@ -136,7 +136,11 @@
                 png = true;
                 break;
             case 'd':
-                displayId = PhysicalDisplayId(atoll(optarg));
+                displayId = DisplayId::fromValue(atoll(optarg));
+                if (!displayId) {
+                    fprintf(stderr, "Invalid display ID\n");
+                    return 1;
+                }
                 break;
             case '?':
             case 'h':
@@ -182,7 +186,7 @@
     ProcessState::self()->startThreadPool();
 
     sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-    status_t result = ScreenshotClient::captureDisplay(displayId->value, captureListener);
+    status_t result = ScreenshotClient::captureDisplay(*displayId, captureListener);
     if (result != NO_ERROR) {
         close(fd);
         return 1;
diff --git a/config/OWNERS b/config/OWNERS
index 0691dbc..c0778f8 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -1,8 +1,8 @@
 include /ZYGOTE_OWNERS
 
 # art-team@ manages the boot image profiles
-per-file boot-* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
-per-file dirty-image-objects = calin@google.com, mathieuc@google.com, ngeoffray@google.com
-per-file generate-preloaded-classes.sh = calin@google.com, mathieuc@google.com, ngeoffray@google.com
-per-file preloaded-classes* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file boot-* = calin@google.com, ngeoffray@google.com, vmarko@google.com
+per-file dirty-image-objects = calin@google.com, ngeoffray@google.com, vmarko@google.com
+per-file generate-preloaded-classes.sh = calin@google.com, ngeoffray@google.com, vmarko@google.com
+per-file preloaded-classes* = calin@google.com, ngeoffray@google.com, vmarko@google.com
 
diff --git a/core/api/current.txt b/core/api/current.txt
index 1de47b5..3d88122 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9429,6 +9429,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
     method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getGroupId(@NonNull android.bluetooth.BluetoothDevice);
     field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
   }
 
@@ -9453,6 +9454,7 @@
     field @Deprecated public static final int HEALTH = 3; // 0x3
     field public static final int HEARING_AID = 21; // 0x15
     field public static final int HID_DEVICE = 19; // 0x13
+    field public static final int LE_AUDIO = 22; // 0x16
     field public static final int SAP = 10; // 0xa
     field public static final int STATE_CONNECTED = 2; // 0x2
     field public static final int STATE_CONNECTING = 1; // 0x1
@@ -11175,11 +11177,13 @@
     field public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
     field public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
     field public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES";
+    field public static final String CATEGORY_APP_FITNESS = "android.intent.category.APP_FITNESS";
     field public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
     field public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
     field public static final String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
     field public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
     field public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
+    field public static final String CATEGORY_APP_WEATHER = "android.intent.category.APP_WEATHER";
     field public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
     field public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
     field public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
@@ -12545,6 +12549,7 @@
     method public abstract int getInstantAppCookieMaxBytes();
     method @NonNull public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract android.content.Intent getLaunchIntentForPackage(@NonNull String);
+    method @NonNull public android.content.IntentSender getLaunchIntentSenderForPackage(@NonNull String);
     method @Nullable public abstract android.content.Intent getLeanbackLaunchIntentForPackage(@NonNull String);
     method @NonNull public java.util.Set<java.lang.String> getMimeGroup(@NonNull String);
     method @NonNull public android.content.pm.ModuleInfo getModuleInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -31070,8 +31075,8 @@
     ctor public Environment();
     method public static java.io.File getDataDirectory();
     method public static java.io.File getDownloadCacheDirectory();
-    method @Deprecated public static java.io.File getExternalStorageDirectory();
-    method @Deprecated public static java.io.File getExternalStoragePublicDirectory(String);
+    method public static java.io.File getExternalStorageDirectory();
+    method public static java.io.File getExternalStoragePublicDirectory(String);
     method public static String getExternalStorageState();
     method public static String getExternalStorageState(java.io.File);
     method @NonNull public static java.io.File getRootDirectory();
@@ -51019,6 +51024,7 @@
     method public CharSequence getClassName();
     method public CharSequence getContentDescription();
     method public int getCurrentItemIndex();
+    method public int getDisplayId();
     method public int getFromIndex();
     method public int getItemCount();
     method public int getMaxScrollX();
@@ -51435,6 +51441,7 @@
 
   public final class AutofillManager {
     method public void cancel();
+    method public void clearAutofillRequestCallback();
     method public void commit();
     method public void disableAutofillServices();
     method @Nullable public android.content.ComponentName getAutofillServiceComponentName();
@@ -51460,6 +51467,7 @@
     method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
     method public void requestAutofill(@NonNull android.view.View);
     method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
+    method public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback);
     method public void setUserData(@Nullable android.service.autofill.UserData);
     method public void unregisterCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
     field public static final String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
@@ -51478,6 +51486,10 @@
     field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
   }
 
+  public interface AutofillRequestCallback {
+    method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
+  }
+
   public final class AutofillValue implements android.os.Parcelable {
     method public int describeContents();
     method public static android.view.autofill.AutofillValue forDate(long);
@@ -51848,10 +51860,12 @@
     ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build();
+    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int);
+    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList);
   }
 
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e48a1da..b22a83d 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -266,6 +266,10 @@
     field public static final int VPN_UID = 1016; // 0x3f8
   }
 
+  public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
+    method @NonNull public static android.os.SharedMemory create(@NonNull android.os.ParcelFileDescriptor);
+  }
+
   public class StatsServiceManager {
     method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
     method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2d73aa6..6aae9ad 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2087,6 +2087,7 @@
     field public static final int PBAP_CLIENT = 17; // 0x11
     field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
     field @Deprecated public static final int PRIORITY_ON = 100; // 0x64
+    field public static final int VOLUME_CONTROL = 23; // 0x17
   }
 
   public final class BluetoothStatusCodes {
@@ -2127,6 +2128,16 @@
     field @NonNull public static final android.os.ParcelUuid VOLUME_CONTROL;
   }
 
+  public final class BluetoothVolumeControl implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setVolume(@Nullable android.bluetooth.BluetoothDevice, @IntRange(from=0, to=255) int);
+    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED";
+  }
+
   public final class BufferConstraint implements android.os.Parcelable {
     ctor public BufferConstraint(int, int, int);
     method public int describeContents();
@@ -2848,7 +2859,7 @@
     field public static final int PROTECTION_FLAG_APP_PREDICTOR = 2097152; // 0x200000
     field public static final int PROTECTION_FLAG_COMPANION = 8388608; // 0x800000
     field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
-    field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
+    field @Deprecated public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
     field public static final int PROTECTION_FLAG_KNOWN_SIGNER = 134217728; // 0x8000000
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
@@ -3297,7 +3308,9 @@
     method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerControlMode();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerStateChangeOnActiveSourceLost();
+    method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getRoutingControl();
     method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
+    method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioControl();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioModeMuting();
     method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getTvSendStandbyOnSleep();
@@ -3313,7 +3326,9 @@
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVolumeControlEnabled(int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setPowerControlMode(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setPowerStateChangeOnActiveSourceLost(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setRoutingControl(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioControl(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioModeMuting(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvSendStandbyOnSleep(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvWakeOnOneTouchPlay(@NonNull int);
@@ -3323,6 +3338,8 @@
     field public static final String CEC_SETTING_NAME_HDMI_CEC_VERSION = "hdmi_cec_version";
     field public static final String CEC_SETTING_NAME_POWER_CONTROL_MODE = "power_control_mode";
     field public static final String CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST = "power_state_change_on_active_source_lost";
+    field public static final String CEC_SETTING_NAME_ROUTING_CONTROL = "routing_control";
+    field public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL = "system_audio_control";
     field public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING = "system_audio_mode_muting";
     field public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP = "tv_send_standby_on_sleep";
     field public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY = "tv_wake_on_one_touch_play";
@@ -3380,6 +3397,7 @@
     field public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast";
     field public static final String POWER_CONTROL_MODE_NONE = "none";
     field public static final String POWER_CONTROL_MODE_TV = "to_tv";
+    field public static final String POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM = "to_tv_and_audio_system";
     field public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE = "none";
     field public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW = "standby_now";
     field public static final int POWER_STATUS_ON = 0; // 0x0
@@ -3395,6 +3413,10 @@
     field public static final int RESULT_SUCCESS = 0; // 0x0
     field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
     field public static final int RESULT_TIMEOUT = 1; // 0x1
+    field public static final int ROUTING_CONTROL_DISABLED = 0; // 0x0
+    field public static final int ROUTING_CONTROL_ENABLED = 1; // 0x1
+    field public static final int SYSTEM_AUDIO_CONTROL_DISABLED = 0; // 0x0
+    field public static final int SYSTEM_AUDIO_CONTROL_ENABLED = 1; // 0x1
     field public static final int SYSTEM_AUDIO_MODE_MUTING_DISABLED = 0; // 0x0
     field public static final int SYSTEM_AUDIO_MODE_MUTING_ENABLED = 1; // 0x1
     field public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 3; // 0x3
@@ -5388,6 +5410,8 @@
     field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
     field public static final int MIX_STATE_IDLE = 0; // 0x0
     field public static final int MIX_STATE_MIXING = 1; // 0x1
+    field public static final int MIX_TYPE_PLAYERS = 0; // 0x0
+    field public static final int MIX_TYPE_RECORDERS = 1; // 0x1
     field public static final int ROUTE_FLAG_LOOP_BACK = 2; // 0x2
     field public static final int ROUTE_FLAG_RENDER = 1; // 0x1
   }
@@ -5401,6 +5425,7 @@
   }
 
   public class AudioMixingRule {
+    method public int getTargetMixType();
     field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
     field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
     field public static final int RULE_MATCH_UID = 4; // 0x4
@@ -5415,6 +5440,7 @@
     method public android.media.audiopolicy.AudioMixingRule build();
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder setTargetMixType(int);
   }
 
   public class AudioPolicy {
@@ -8059,8 +8085,8 @@
   }
 
   public final class BatteryStatsManager {
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats();
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.BATTERY_STATS, android.Manifest.permission.UPDATE_DEVICE_STATS}) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.BATTERY_STATS, android.Manifest.permission.UPDATE_DEVICE_STATS}) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean, int);
@@ -9105,6 +9131,7 @@
     field public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
     field @Deprecated public static final String NAMESPACE_STORAGE = "storage";
     field public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
+    field public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native";
     field public static final String NAMESPACE_SYSTEMUI = "systemui";
     field public static final String NAMESPACE_SYSTEM_TIME = "system_time";
     field public static final String NAMESPACE_TELEPHONY = "telephony";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a4ac61b..1ff834d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1270,6 +1270,12 @@
 
 package android.inputmethodservice {
 
+  public abstract class AbstractInputMethodService extends android.window.WindowProviderService implements android.view.KeyEvent.Callback {
+    method public final int getInitialDisplayId();
+    method @Nullable public final android.os.Bundle getWindowContextOptions();
+    method public final int getWindowType();
+  }
+
   @UiContext public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
     field public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // 0x94fa793L
   }
@@ -1386,6 +1392,7 @@
 package android.media {
 
   public final class AudioAttributes implements android.os.Parcelable {
+    method public static int[] getSdkUsages();
     method @NonNull public static String usageToXsdString(int);
     method public static int xsdStringToUsage(@NonNull String);
   }
@@ -1410,6 +1417,8 @@
     method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int abandonAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String);
     method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
     method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
+    method public static final int[] getPublicStreamTypes();
+    method public int getStreamMinVolumeInt(int);
     method @NonNull public java.util.Map<java.lang.Integer,java.lang.Boolean> getSurroundFormats();
     method public boolean hasRegisteredDynamicPolicy();
     method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE}) public boolean isFullVolumeDevice();
@@ -1434,6 +1443,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public static float getMasterBalance();
     method public static final int getNumStreamTypes();
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public static int setMasterBalance(float);
+    method @NonNull public static String streamToString(int);
     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
@@ -1531,6 +1541,13 @@
     method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean);
   }
 
+  public final class AudioProductStrategy implements android.os.Parcelable {
+    method @NonNull public static android.media.AudioAttributes getDefaultAttributes();
+    method public int getLegacyStreamTypeForAudioAttributes(@NonNull android.media.AudioAttributes);
+    method public int getVolumeGroupIdForAudioAttributes(@NonNull android.media.AudioAttributes);
+    method public int getVolumeGroupIdForLegacyStreamType(int);
+  }
+
 }
 
 package android.media.metrics {
@@ -2109,6 +2126,7 @@
   public final class DeviceConfig {
     field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
     field public static final String NAMESPACE_ANDROID = "android";
+    field public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
     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";
@@ -2852,6 +2870,10 @@
     method public long getAccessibilityIdForRegion(@NonNull android.graphics.Region);
   }
 
+  public class AccessibilityRecord {
+    method public void setDisplayId(int);
+  }
+
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
   }
@@ -3244,6 +3266,7 @@
   @UiContext public abstract class WindowProviderService extends android.app.Service {
     ctor public WindowProviderService();
     method public final void attachToWindowToken(@NonNull android.os.IBinder);
+    method @NonNull public int getInitialDisplayId();
     method @Nullable public android.os.Bundle getWindowContextOptions();
     method public abstract int getWindowType();
   }
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 5409165..e3690e5 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -71,6 +71,10 @@
     
 
 
+AllUpper: android.media.audiopolicy.AudioProductStrategy#sDefaultAttributes:
+    Constant field names must be named with only upper case characters: `android.media.audiopolicy.AudioProductStrategy#sDefaultAttributes`, should be `S_DEFAULT_ATTRIBUTES`?
+
+
 ArrayReturn: android.app.UiAutomation#executeShellCommandRw(String):
     
 ArrayReturn: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#KeyphraseSoundModel(java.util.UUID, java.util.UUID, byte[], android.hardware.soundtrigger.SoundTrigger.Keyphrase[]) parameter #3:
@@ -537,6 +541,8 @@
     
 
 
+InternalField: android.media.audiopolicy.AudioProductStrategy#sDefaultAttributes:
+    Internal field sDefaultAttributes must not be exposed
 InternalField: android.telephony.ims.ImsConferenceState#mParticipants:
     
 
@@ -1045,8 +1051,14 @@
     
 MissingNullability: android.location.LocationRequest#writeToParcel(android.os.Parcel, int) parameter #0:
     
+MissingNullability: android.media.AudioAttributes#SDK_USAGES:
+    Missing nullability on field `SDK_USAGES` in class `class android.media.AudioAttributes`
+MissingNullability: android.media.AudioAttributes#getSdkUsages():
+    Missing nullability on method `getSdkUsages` return
 MissingNullability: android.media.AudioFocusInfo#writeToParcel(android.os.Parcel, int) parameter #0:
     
+MissingNullability: android.media.AudioManager#getPublicStreamTypes():
+    Missing nullability on method `getPublicStreamTypes` return
 MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #3:
     
 MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #4:
@@ -1063,6 +1075,8 @@
     
 MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #6:
     
+MissingNullability: android.media.AudioSystem#streamToString(int):
+    Missing nullability on method `streamToString` return
 MissingNullability: android.media.PlaybackParams#setAudioStretchMode(int):
     
 MissingNullability: android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL:
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index e91209c..ddbe302 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -16,6 +16,8 @@
 
 package android.accessibilityservice;
 
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+
 import android.accessibilityservice.GestureDescription.MotionEventGenerator;
 import android.annotation.CallbackExecutor;
 import android.annotation.ColorInt;
@@ -27,6 +29,7 @@
 import android.app.Service;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Bitmap;
@@ -36,6 +39,7 @@
 import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayManager;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -102,14 +106,14 @@
  * An accessibility is declared as any other service in an AndroidManifest.xml, but it
  * must do two things:
  * <ul>
- *     <ol>
+ *     <li>
  *         Specify that it handles the "android.accessibilityservice.AccessibilityService"
  *         {@link android.content.Intent}.
- *     </ol>
- *     <ol>
+ *     </li>
+ *     <li>
  *         Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
  *         ensure that only the system can bind to it.
- *     </ol>
+ *     </li>
  * </ul>
  * If either of these items is missing, the system will ignore the accessibility service.
  * Following is an example declaration:
@@ -961,30 +965,31 @@
         }
     }
 
+    @NonNull
     @Override
     public Context createDisplayContext(Display display) {
-        final Context context = super.createDisplayContext(display);
-        final int displayId = display.getDisplayId();
-        setDefaultTokenInternal(context, displayId);
-        return context;
+        return new AccessibilityContext(super.createDisplayContext(display), mConnectionId);
     }
 
-    private void setDefaultTokenInternal(Context context, int displayId) {
-        final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService(WINDOW_SERVICE);
-        final IAccessibilityServiceConnection connection =
-                AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId);
-        IBinder token = null;
-        if (connection != null) {
-            synchronized (mLock) {
-                try {
-                    token = connection.getOverlayWindowToken(displayId);
-                } catch (RemoteException re) {
-                    Log.w(LOG_TAG, "Failed to get window token", re);
-                    re.rethrowFromSystemServer();
-                }
-            }
-            wm.setDefaultToken(token);
+    @NonNull
+    @Override
+    public Context createWindowContext(int type, @Nullable Bundle options) {
+        final Context context = super.createWindowContext(type, options);
+        if (type != TYPE_ACCESSIBILITY_OVERLAY) {
+            return context;
         }
+        return new AccessibilityContext(context, mConnectionId);
+    }
+
+    @NonNull
+    @Override
+    public Context createWindowContext(@NonNull Display display, int type,
+            @Nullable Bundle options) {
+        final Context context = super.createWindowContext(display, type, options);
+        if (type != TYPE_ACCESSIBILITY_OVERLAY) {
+            return context;
+        }
+        return new AccessibilityContext(context, mConnectionId);
     }
 
     /**
@@ -2400,6 +2405,14 @@
                     if (connection != null) {
                         AccessibilityInteractionClient.getInstance(mContext).addConnection(
                                 mConnectionId, connection);
+                        if (mContext != null) {
+                            try {
+                                connection.setAttributionTag(mContext.getAttributionTag());
+                            } catch (RemoteException re) {
+                                Log.w(LOG_TAG, "Error while setting attributionTag", re);
+                                re.rethrowFromSystemServer();
+                            }
+                        }
                         mCallback.init(mConnectionId, windowToken);
                         mCallback.onServiceConnected();
                     } else {
@@ -2675,4 +2688,58 @@
             }
         }
     }
+
+    private static class AccessibilityContext extends ContextWrapper {
+        private final int mConnectionId;
+
+        private AccessibilityContext(Context base, int connectionId) {
+            super(base);
+            mConnectionId = connectionId;
+            setDefaultTokenInternal(this, getDisplayId());
+        }
+
+        @NonNull
+        @Override
+        public Context createDisplayContext(Display display) {
+            return new AccessibilityContext(super.createDisplayContext(display), mConnectionId);
+        }
+
+        @NonNull
+        @Override
+        public Context createWindowContext(int type, @Nullable Bundle options) {
+            final Context context = super.createWindowContext(type, options);
+            if (type != TYPE_ACCESSIBILITY_OVERLAY) {
+                return context;
+            }
+            return new AccessibilityContext(context, mConnectionId);
+        }
+
+        @NonNull
+        @Override
+        public Context createWindowContext(@NonNull Display display, int type,
+                @Nullable Bundle options) {
+            final Context context = super.createWindowContext(display, type, options);
+            if (type != TYPE_ACCESSIBILITY_OVERLAY) {
+                return context;
+            }
+            return new AccessibilityContext(context, mConnectionId);
+        }
+
+        private void setDefaultTokenInternal(Context context, int displayId) {
+            final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService(
+                    WINDOW_SERVICE);
+            final IAccessibilityServiceConnection connection =
+                    AccessibilityInteractionClient.getConnection(mConnectionId);
+            IBinder token = null;
+            if (connection != null) {
+                try {
+                    token = connection.getOverlayWindowToken(displayId);
+                } catch (RemoteException re) {
+                    Log.w(LOG_TAG, "Failed to get window token", re);
+                    re.rethrowFromSystemServer();
+                }
+                wm.setDefaultToken(token);
+            }
+        }
+    }
 }
diff --git a/core/java/android/accessibilityservice/AccessibilityTrace.java b/core/java/android/accessibilityservice/AccessibilityTrace.java
new file mode 100644
index 0000000..f28015a
--- /dev/null
+++ b/core/java/android/accessibilityservice/AccessibilityTrace.java
@@ -0,0 +1,216 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.accessibilityservice;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interface to log accessibility trace.
+ *
+ * @hide
+ */
+public interface AccessibilityTrace {
+    String NAME_ACCESSIBILITY_SERVICE_CONNECTION = "IAccessibilityServiceConnection";
+    String NAME_ACCESSIBILITY_SERVICE_CLIENT = "IAccessibilityServiceClient";
+    String NAME_ACCESSIBILITY_MANAGER = "IAccessibilityManager";
+    String NAME_ACCESSIBILITY_MANAGER_CLIENT = "IAccessibilityManagerClient";
+    String NAME_ACCESSIBILITY_INTERACTION_CONNECTION = "IAccessibilityInteractionConnection";
+    String NAME_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK =
+            "IAccessibilityInteractionConnectionCallback";
+    String NAME_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK = "IRemoteMagnificationAnimationCallback";
+    String NAME_WINDOW_MAGNIFICATION_CONNECTION = "IWindowMagnificationConnection";
+    String NAME_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK = "IWindowMagnificationConnectionCallback";
+    String NAME_WINDOW_MANAGER_INTERNAL = "WindowManagerInternal";
+    String NAME_WINDOWS_FOR_ACCESSIBILITY_CALLBACK = "WindowsForAccessibilityCallback";
+    String NAME_MAGNIFICATION_CALLBACK = "MagnificationCallbacks";
+    String NAME_INPUT_FILTER = "InputFilter";
+    String NAME_GESTURE = "Gesture";
+    String NAME_ACCESSIBILITY_SERVICE = "AccessibilityService";
+    String NAME_PACKAGE_BROADCAST_RECEIVER = "PMBroadcastReceiver";
+    String NAME_USER_BROADCAST_RECEIVER = "UserBroadcastReceiver";
+    String NAME_FINGERPRINT = "FingerprintGesture";
+    String NAME_ACCESSIBILITY_INTERACTION_CLIENT = "AccessibilityInteractionClient";
+
+    String NAME_ALL_LOGGINGS = "AllLoggings";
+    String NAME_NONE = "None";
+
+    long FLAGS_ACCESSIBILITY_SERVICE_CONNECTION = 0x0000000000000001L;
+    long FLAGS_ACCESSIBILITY_SERVICE_CLIENT = 0x0000000000000002L;
+    long FLAGS_ACCESSIBILITY_MANAGER = 0x0000000000000004L;
+    long FLAGS_ACCESSIBILITY_MANAGER_CLIENT = 0x0000000000000008L;
+    long FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION = 0x0000000000000010L;
+    long FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK = 0x0000000000000020L;
+    long FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK = 0x0000000000000040L;
+    long FLAGS_WINDOW_MAGNIFICATION_CONNECTION = 0x0000000000000080L;
+    long FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK = 0x0000000000000100L;
+    long FLAGS_WINDOW_MANAGER_INTERNAL = 0x0000000000000200L;
+    long FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK = 0x0000000000000400L;
+    long FLAGS_MAGNIFICATION_CALLBACK = 0x0000000000000800L;
+    long FLAGS_INPUT_FILTER = 0x0000000000001000L;
+    long FLAGS_GESTURE = 0x0000000000002000L;
+    long FLAGS_ACCESSIBILITY_SERVICE = 0x0000000000004000L;
+    long FLAGS_PACKAGE_BROADCAST_RECEIVER = 0x0000000000008000L;
+    long FLAGS_USER_BROADCAST_RECEIVER = 0x0000000000010000L;
+    long FLAGS_FINGERPRINT = 0x0000000000020000L;
+    long FLAGS_ACCESSIBILITY_INTERACTION_CLIENT = 0x0000000000040000L;
+
+    long FLAGS_LOGGING_NONE = 0x0000000000000000L;
+    long FLAGS_LOGGING_ALL = 0xFFFFFFFFFFFFFFFFL;
+
+    long FLAGS_ACCESSIBILITY_MANAGER_CLIENT_STATES = FLAGS_ACCESSIBILITY_INTERACTION_CLIENT
+            | FLAGS_ACCESSIBILITY_SERVICE
+            | FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION
+            | FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK;
+
+    Map<String, Long> sNamesToFlags = Map.ofEntries(
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_SERVICE_CONNECTION, FLAGS_ACCESSIBILITY_SERVICE_CONNECTION),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_SERVICE_CLIENT, FLAGS_ACCESSIBILITY_SERVICE_CLIENT),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_MANAGER, FLAGS_ACCESSIBILITY_MANAGER),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_MANAGER_CLIENT, FLAGS_ACCESSIBILITY_MANAGER_CLIENT),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_INTERACTION_CONNECTION,
+                    FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK,
+                    FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK,
+                    FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_WINDOW_MAGNIFICATION_CONNECTION, FLAGS_WINDOW_MAGNIFICATION_CONNECTION),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_WINDOW_MANAGER_INTERNAL, FLAGS_WINDOW_MANAGER_INTERNAL),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
+                    FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_MAGNIFICATION_CALLBACK, FLAGS_MAGNIFICATION_CALLBACK),
+            new AbstractMap.SimpleEntry<String, Long>(NAME_INPUT_FILTER, FLAGS_INPUT_FILTER),
+            new AbstractMap.SimpleEntry<String, Long>(NAME_GESTURE, FLAGS_GESTURE),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_SERVICE, FLAGS_ACCESSIBILITY_SERVICE),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_PACKAGE_BROADCAST_RECEIVER, FLAGS_PACKAGE_BROADCAST_RECEIVER),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_USER_BROADCAST_RECEIVER, FLAGS_USER_BROADCAST_RECEIVER),
+            new AbstractMap.SimpleEntry<String, Long>(NAME_FINGERPRINT, FLAGS_FINGERPRINT),
+            new AbstractMap.SimpleEntry<String, Long>(
+                    NAME_ACCESSIBILITY_INTERACTION_CLIENT, FLAGS_ACCESSIBILITY_INTERACTION_CLIENT),
+            new AbstractMap.SimpleEntry<String, Long>(NAME_NONE, FLAGS_LOGGING_NONE),
+            new AbstractMap.SimpleEntry<String, Long>(NAME_ALL_LOGGINGS, FLAGS_LOGGING_ALL));
+
+    /**
+     * Get the flags of the logging types by the given names.
+     * The names list contains logging type names in lower case.
+     */
+    static long getLoggingFlagsFromNames(List<String> names) {
+        long types = FLAGS_LOGGING_NONE;
+        for (String name : names) {
+            long flag = sNamesToFlags.get(name);
+            types |= flag;
+        }
+        return types;
+    }
+
+    /**
+     * Get the list of the names of logging types by the given flags.
+     */
+    static List<String> getNamesOfLoggingTypes(long flags) {
+        List<String> list = new ArrayList<String>();
+
+        for (Map.Entry<String, Long> entry : sNamesToFlags.entrySet()) {
+            if ((entry.getValue() & flags) != FLAGS_LOGGING_NONE) {
+                list.add(entry.getKey());
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * Whether the trace is enabled for any logging type.
+     */
+    boolean isA11yTracingEnabled();
+
+    /**
+     * Whether the trace is enabled for any of the given logging type.
+     */
+    boolean isA11yTracingEnabledForTypes(long typeIdFlags);
+
+    /**
+     * Get trace state to be sent to AccessibilityManager.
+     */
+    int getTraceStateForAccessibilityManagerClientState();
+
+    /**
+     * Start tracing for the given logging types.
+     */
+    void startTrace(long flagss);
+
+    /**
+     * Stop tracing.
+     */
+    void stopTrace();
+
+    /**
+     * Log one trace entry.
+     * @param where A string to identify this log entry, which can be used to search through the
+     *        tracing file.
+     * @param loggingFlags Flags to identify which logging types this entry belongs to. This
+     *        can be used to filter the log entries when generating tracing file.
+     */
+    void logTrace(String where, long loggingFlags);
+
+    /**
+     * Log one trace entry.
+     * @param where A string to identify this log entry, which can be used to filter/search
+     *        through the tracing file.
+     * @param loggingFlags Flags to identify which logging types this entry belongs to. This
+     *        can be used to filter the log entries when generating tracing file.
+     * @param callingParams The parameters for the method to be logged.
+     */
+    void logTrace(String where, long loggingFlags, String callingParams);
+
+    /**
+     * Log one trace entry. Accessibility services using AccessibilityInteractionClient to
+     * make screen content related requests use this API to log entry when receive callback.
+     * @param timestamp The timestamp when a callback is received.
+     * @param where A string to identify this log entry, which can be used to filter/search
+     *        through the tracing file.
+     * @param loggingFlags Flags to identify which logging types this entry belongs to. This
+     *        can be used to filter the log entries when generating tracing file.
+     * @param callingParams The parameters for the callback.
+     * @param processId The process id of the calling component.
+     * @param threadId The threadId of the calling component.
+     * @param callingUid The calling uid of the callback.
+     * @param callStack The call stack of the callback.
+     * @param ignoreStackElements ignore these call stack element
+     */
+    void logTrace(long timestamp, String where, long loggingFlags, String callingParams,
+            int processId, long threadId, int callingUid, StackTraceElement[] callStack,
+            Set<String> ignoreStackElements);
+}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 923b6f4..6c360e5 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -39,6 +39,8 @@
 
     void setServiceInfo(in AccessibilityServiceInfo info);
 
+    void setAttributionTag(in String attributionTag);
+
     String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
         long accessibilityNodeId, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
@@ -118,6 +120,6 @@
 
     void setFocusAppearance(int strokeWidth, int color);
 
-    oneway void logTrace(long timestamp, String where, String callingParams, int processId,
-        long threadId, int callingUid, in Bundle serializedCallingStackInBundle);
+    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/Account.java b/core/java/android/accounts/Account.java
index 0d6a079..e6cdcc0 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,6 +31,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -86,6 +87,12 @@
         if (TextUtils.isEmpty(type)) {
             throw new IllegalArgumentException("the type must not be empty: " + type);
         }
+        if (name.length() > 200) {
+            throw new IllegalArgumentException("account name is longer than 200 characters");
+        }
+        if (type.length() > 200) {
+            throw new IllegalArgumentException("account type is longer than 200 characters");
+        }
         this.name = name;
         this.type = type;
         this.accessId = accessId;
diff --git a/core/java/android/accounts/OWNERS b/core/java/android/accounts/OWNERS
index 8dcc04a..6ad9d92 100644
--- a/core/java/android/accounts/OWNERS
+++ b/core/java/android/accounts/OWNERS
@@ -1,9 +1,4 @@
-carlosvaldivia@google.com
+jcivelli@google.com
 dementyev@google.com
-sandrakwan@google.com
-hackbod@google.com
-svetoslavganov@google.com
-fkupolov@google.com
 yamasani@google.com
 omakoto@google.com
-
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 4a7fcd2..a836625 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -476,6 +476,19 @@
     }
 
     /**
+     * Detaches the navigation bar from the app it was attached to during a transition.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
+    public void detachNavigationBarFromApp(@NonNull IBinder transition) {
+        try {
+            getService().detachNavigationBarFromApp(transition);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Information you can retrieve about a root task in the system.
      * @hide
      */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4182ac3..0df4bf3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
 import static android.app.ConfigurationController.createNewConfigAndUpdateIfNotNull;
-import static android.app.ConfigurationController.freeTextLayoutCachesIfNeeded;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
@@ -31,6 +30,10 @@
 import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
 import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets;
+import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
+import static android.window.ConfigurationHelper.isDifferentDisplay;
+import static android.window.ConfigurationHelper.shouldUpdateResources;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 
@@ -88,10 +91,8 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.HardwareRenderer;
-import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.hardware.display.DisplayManagerGlobal;
-import android.inputmethodservice.InputMethodService;
 import android.media.MediaFrameworkInitializer;
 import android.media.MediaFrameworkPlatformInitializer;
 import android.media.MediaServiceManager;
@@ -183,6 +184,7 @@
 import android.window.SizeConfigurationBuckets;
 import android.window.SplashScreen;
 import android.window.SplashScreenView;
+import android.window.WindowProviderService;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -5919,7 +5921,7 @@
     }
 
     @Override
-    public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities) {
+    public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts) {
         ArrayList<ComponentCallbacks2> callbacks
                 = new ArrayList<ComponentCallbacks2>();
 
@@ -5928,7 +5930,7 @@
             for (int i=0; i<NAPP; i++) {
                 callbacks.add(mAllApplications.get(i));
             }
-            if (includeActivities) {
+            if (includeUiContexts) {
                 for (int i = mActivities.size() - 1; i >= 0; i--) {
                     final Activity a = mActivities.valueAt(i).activity;
                     if (a != null && !a.mFinished) {
@@ -5938,11 +5940,12 @@
             }
             final int NSVC = mServices.size();
             for (int i=0; i<NSVC; i++) {
-                final ComponentCallbacks2 serviceComp = mServices.valueAt(i);
-                if (serviceComp instanceof InputMethodService) {
-                    mHasImeComponent = true;
+                final Service service = mServices.valueAt(i);
+                // If {@code includeUiContext} is set to false, WindowProviderService should not be
+                // collected because WindowProviderService is a UI Context.
+                if (includeUiContexts || !(service instanceof WindowProviderService)) {
+                    callbacks.add(service);
                 }
-                callbacks.add(serviceComp);
             }
         }
         synchronized (mProviderMap) {
@@ -5997,35 +6000,26 @@
         // change callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
         handleWindowingModeChangeIfNeeded(activity, newConfig);
 
-        final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
-        boolean shouldReportChange = false;
-        if (activity.mCurrentConfig == null) {
-            shouldReportChange = true;
-        } else {
-            // If the new config is the same as the config this Activity is already running with and
-            // the override config also didn't change, then don't bother calling
-            // onConfigurationChanged.
-            // TODO(b/173090263): Use diff instead after the improvement of AssetManager and
-            // ResourcesImpl constructions.
-            int diff = activity.mCurrentConfig.diffPublicOnly(newConfig);
-            final ActivityClientRecord cr = getActivityClient(activityToken);
-            diff = SizeConfigurationBuckets.filterDiff(diff, activity.mCurrentConfig, newConfig,
-                    cr != null ? cr.mSizeConfigurations : null);
-
-            if (diff == 0) {
-                if (!shouldUpdateWindowMetricsBounds(activity.mCurrentConfig, newConfig)
-                        && !movedToDifferentDisplay
-                        && mResourcesManager.isSameResourcesOverrideConfig(
-                                activityToken, amOverrideConfig)) {
-                    // Nothing significant, don't proceed with updating and reporting.
-                    return null;
-                }
-            } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
+        final boolean movedToDifferentDisplay = isDifferentDisplay(activity.getDisplayId(),
+                displayId);
+        final SizeConfigurationBuckets buckets = getActivityClient(activityToken)
+                .mSizeConfigurations;
+        final int diff = diffPublicWithSizeBuckets(activity.mCurrentConfig,
+                newConfig, buckets);
+        final boolean hasPublicConfigChange = diff != 0;
+        // TODO(b/173090263): Use diff instead after the improvement of AssetManager and
+        // ResourcesImpl constructions.
+        final boolean shouldUpdateResources = hasPublicConfigChange
+                || shouldUpdateResources(activityToken, activity.mCurrentConfig, newConfig,
+                amOverrideConfig, movedToDifferentDisplay, hasPublicConfigChange);
+        final boolean shouldReportChange = hasPublicConfigChange
                 // If this activity doesn't handle any of the config changes, then don't bother
                 // calling onConfigurationChanged. Otherwise, report to the activity for the
                 // changes.
-                shouldReportChange = true;
-            }
+                && (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0;
+        // Nothing significant, don't proceed with updating and reporting.
+        if (!shouldUpdateResources) {
+            return null;
         }
 
         // Propagate the configuration change to ResourcesManager and Activity.
@@ -6076,26 +6070,6 @@
         return configToReport;
     }
 
-    // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl
-    // constructions.
-    /**
-     * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs
-     * should be updated.
-     *
-     * @see WindowManager#getCurrentWindowMetrics()
-     * @see WindowManager#getMaximumWindowMetrics()
-     */
-    private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
-            @NonNull Configuration newConfig) {
-        final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
-        final Rect newBounds = newConfig.windowConfiguration.getBounds();
-
-        final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds();
-        final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds();
-
-        return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds);
-    }
-
     public final void applyConfigurationToResources(Configuration config) {
         synchronized (mResourcesManager) {
             mResourcesManager.applyConfigurationToResources(config, null);
@@ -6213,7 +6187,8 @@
             // display.
             displayId = r.activity.getDisplayId();
         }
-        final boolean movedToDifferentDisplay = isDifferentDisplay(r.activity, displayId);
+        final boolean movedToDifferentDisplay = isDifferentDisplay(
+                r.activity.getDisplayId(), displayId);
         if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
                 && !movedToDifferentDisplay) {
             if (DEBUG_CONFIGURATION) {
@@ -6249,14 +6224,6 @@
         mSomeActivitiesChanged = true;
     }
 
-    /**
-     * Checks if the display id of activity is different from the given one. Note that
-     * {@link Display#INVALID_DISPLAY} means no difference.
-     */
-    private static boolean isDifferentDisplay(@NonNull Activity activity, int displayId) {
-        return displayId != INVALID_DISPLAY && displayId != activity.getDisplayId();
-    }
-
     final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
         if (start) {
             try {
@@ -6363,7 +6330,7 @@
 
     final void handleLowMemory() {
         final ArrayList<ComponentCallbacks2> callbacks =
-                collectComponentCallbacks(true /* includeActivities */);
+                collectComponentCallbacks(true /* includeUiContexts */);
 
         final int N = callbacks.size();
         for (int i=0; i<N; i++) {
@@ -6396,7 +6363,7 @@
         }
 
         final ArrayList<ComponentCallbacks2> callbacks =
-                collectComponentCallbacks(true /* includeActivities */);
+                collectComponentCallbacks(true /* includeUiContexts */);
 
         final int N = callbacks.size();
         for (int i = 0; i < N; i++) {
@@ -7615,12 +7582,6 @@
 
         ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
             synchronized (mResourcesManager) {
-                // TODO (b/135719017): Temporary log for debugging IME service.
-                if (Build.IS_DEBUGGABLE && mHasImeComponent) {
-                    Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, "
-                            + "config=" + globalConfig);
-                }
-
                 // We need to apply this change to the resources immediately, because upon returning
                 // the view hierarchy will be informed about it.
                 if (mResourcesManager.applyConfigurationToResources(globalConfig,
@@ -7975,11 +7936,6 @@
         return mDensityCompatMode;
     }
 
-    @Override
-    public boolean hasImeComponent() {
-        return mHasImeComponent;
-    }
-
     // ------------------ Regular JNI ------------------------
     private native void nPurgePendingResources();
     private native void nDumpGraphicsInfo(FileDescriptor fd);
diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java
index d91933c..bc698f6 100644
--- a/core/java/android/app/ActivityThreadInternal.java
+++ b/core/java/android/app/ActivityThreadInternal.java
@@ -32,11 +32,9 @@
 
     boolean isInDensityCompatMode();
 
-    boolean hasImeComponent();
-
     boolean isCachedProcessState();
 
     Application getApplication();
 
-    ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities);
+    ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeUiContexts);
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index cd2c12c..2d172c5 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -317,6 +317,16 @@
     }
 
     @Override
+    public @NonNull IntentSender getLaunchIntentSenderForPackage(@NonNull String packageName) {
+        try {
+            return mPM.getLaunchIntentSenderForPackage(packageName, mContext.getPackageName(),
+                    mContext.getAttributionTag(), getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         return getPackageGids(packageName, 0);
     }
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
index f79e078..8637e31 100644
--- a/core/java/android/app/ConfigurationController.java
+++ b/core/java/android/app/ConfigurationController.java
@@ -17,24 +17,20 @@
 package android.app;
 
 import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.HardwareRenderer;
-import android.inputmethodservice.InputMethodService;
-import android.os.Build;
 import android.os.LocaleList;
 import android.os.Trace;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.util.Slog;
 import android.view.ContextThemeWrapper;
 import android.view.WindowManagerGlobal;
@@ -169,12 +165,7 @@
                 mPendingConfiguration = null;
             }
 
-            final boolean hasIme = mActivityThread.hasImeComponent();
             if (config == null) {
-                // TODO (b/135719017): Temporary log for debugging IME service.
-                if (Build.IS_DEBUGGABLE && hasIme) {
-                    Log.w(TAG, "handleConfigurationChanged for IME app but config is null");
-                }
                 return;
             }
 
@@ -205,12 +196,6 @@
                 mConfiguration = new Configuration();
             }
             if (!mConfiguration.isOtherSeqNewer(config) && compat == null) {
-                // TODO (b/135719017): Temporary log for debugging IME service.
-                if (Build.IS_DEBUGGABLE && hasIme) {
-                    Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete "
-                            + ", config=" + config
-                            + ", mConfiguration=" + mConfiguration);
-                }
                 return;
             }
 
@@ -228,7 +213,7 @@
         }
 
         final ArrayList<ComponentCallbacks2> callbacks =
-                mActivityThread.collectComponentCallbacks(false /* includeActivities */);
+                mActivityThread.collectComponentCallbacks(false /* includeUiContexts */);
 
         freeTextLayoutCachesIfNeeded(configDiff);
 
@@ -238,13 +223,6 @@
                 ComponentCallbacks2 cb = callbacks.get(i);
                 if (!equivalent) {
                     performConfigurationChanged(cb, config);
-                } else {
-                    // TODO (b/135719017): Temporary log for debugging IME service.
-                    if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) {
-                        Log.w(TAG, "performConfigurationChanged didn't callback to IME "
-                                + ", configDiff=" + configDiff
-                                + ", mConfiguration=" + mConfiguration);
-                    }
                 }
             }
         }
@@ -326,16 +304,4 @@
         return newConfig;
     }
 
-    /** Ask test layout engine to free its caches if there is a locale change. */
-    static void freeTextLayoutCachesIfNeeded(int configDiff) {
-        if (configDiff != 0) {
-            boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0);
-            if (hasLocaleConfigChange) {
-                Canvas.freeTextLayoutCaches();
-                if (DEBUG_CONFIGURATION) {
-                    Slog.v(TAG, "Cleared TextLayout Caches");
-                }
-            }
-        }
-    }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d241968..8de0367 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3186,12 +3186,6 @@
     @UnsupportedAppUsage
     final void setOuterContext(@NonNull Context context) {
         mOuterContext = context;
-        // TODO(b/149463653): check if we still need this method after migrating IMS to
-        //  WindowContext.
-        if (mOuterContext.isUiContext() && mContextType <= CONTEXT_TYPE_DISPLAY_CONTEXT) {
-            mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
-            mIsConfigurationBasedContext = true;
-        }
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 74d51a0..9f97fad 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -330,4 +330,10 @@
      * When the Picture-in-picture state has changed.
      */
     void onPictureInPictureStateChanged(in PictureInPictureUiState pipState);
+
+    /**
+     * Re-attach navbar to the display during a recents transition.
+     * TODO(188595497): Remove this once navbar attachment is in shell.
+     */
+    void detachNavigationBarFromApp(in IBinder transition);
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6454d20..86ea05b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5538,12 +5538,11 @@
 
         /**
          * Determines if the notification should be colorized *for the purposes of applying colors*.
-         * If this is the minimized view of a colorized notification, or if the app did not provide
-         * a color to colorize with, this will return false so that internal coloring logic can
-         * still render the notification normally.
+         * If this is the minimized view of a colorized notification, this will return false so that
+         * internal coloring logic can still render the notification normally.
          */
         private boolean isBackgroundColorized(StandardTemplateParams p) {
-            return p.allowColorization && mN.color != COLOR_DEFAULT && mN.isColorized();
+            return p.allowColorization && mN.isColorized();
         }
 
         private boolean isCallActionColorCustomizable() {
@@ -5551,8 +5550,7 @@
             //  that is only used for disallowing colorization of headers for the minimized state,
             //  and neither of those conditions applies when showing actions.
             //  Not requiring StandardTemplateParams as an argument simplifies the creation process.
-            return mN.color != COLOR_DEFAULT && mN.isColorized()
-                    && mContext.getResources().getBoolean(
+            return mN.isColorized() && mContext.getResources().getBoolean(
                     R.bool.config_callNotificationActionColorsRequireColorized);
         }
 
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index dfd1e2b..5af18355 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -692,7 +692,7 @@
      * @return true if activity resources override config matches the provided one or they are both
      *         null, false otherwise.
      */
-    boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken,
+    public boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken,
             @Nullable Configuration overrideConfig) {
         synchronized (mLock) {
             final ActivityResources activityResources
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index b95412f..3d32e00 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -117,6 +118,12 @@
     public int displayId;
 
     /**
+     * The feature id of {@link com.android.server.wm.TaskDisplayArea} this task is associated with.
+     * @hide
+     */
+    public int displayAreaFeatureId = FEATURE_UNDEFINED;
+
+    /**
      * The recent activity values for the highest activity in the stack to have set the values.
      * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
      */
@@ -239,6 +246,12 @@
      */
     public boolean isVisible;
 
+    /**
+     * Whether this task is sleeping due to sleeping display.
+     * @hide
+     */
+    public boolean isSleeping;
+
     TaskInfo() {
         // Do nothing
     }
@@ -325,11 +338,10 @@
     }
 
     /**
-      * Returns {@code true} if parameters that are important for task organizers have changed
-      * and {@link com.android.server.wm.TaskOrginizerController} needs to notify listeners
-      * about that.
-      * @hide
-      */
+     * Returns {@code true} if the parameters that are important for task organizers are equal
+     * between this {@link TaskInfo} and {@param that}.
+     * @hide
+     */
     public boolean equalsForTaskOrganizer(@Nullable TaskInfo that) {
         if (that == null) {
             return false;
@@ -337,12 +349,14 @@
         return topActivityType == that.topActivityType
                 && isResizeable == that.isResizeable
                 && supportsMultiWindow == that.supportsMultiWindow
+                && displayAreaFeatureId == that.displayAreaFeatureId
                 && Objects.equals(positionInParent, that.positionInParent)
                 && Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
                 && getWindowingMode() == that.getWindowingMode()
                 && Objects.equals(taskDescription, that.taskDescription)
                 && isFocused == that.isFocused
-                && isVisible == that.isVisible;
+                && isVisible == that.isVisible
+                && isSleeping == that.isSleeping;
     }
 
     /**
@@ -396,9 +410,11 @@
         parentTaskId = source.readInt();
         isFocused = source.readBoolean();
         isVisible = source.readBoolean();
+        isSleeping = source.readBoolean();
         topActivityToken = source.readStrongBinder();
         topActivityInSizeCompat = source.readBoolean();
         mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
+        displayAreaFeatureId = source.readInt();
     }
 
     /**
@@ -434,9 +450,11 @@
         dest.writeInt(parentTaskId);
         dest.writeBoolean(isFocused);
         dest.writeBoolean(isVisible);
+        dest.writeBoolean(isSleeping);
         dest.writeStrongBinder(topActivityToken);
         dest.writeBoolean(topActivityInSizeCompat);
         dest.writeTypedObject(mTopActivityLocusId, flags);
+        dest.writeInt(displayAreaFeatureId);
     }
 
     @Override
@@ -462,9 +480,11 @@
                 + " parentTaskId=" + parentTaskId
                 + " isFocused=" + isFocused
                 + " isVisible=" + isVisible
+                + " isSleeping=" + isSleeping
                 + " topActivityToken=" + topActivityToken
                 + " topActivityInSizeCompat=" + topActivityInSizeCompat
-                + " locusId= " + mTopActivityLocusId
+                + " locusId=" + mTopActivityLocusId
+                + " displayAreaFeatureId=" + displayAreaFeatureId
                 + "}";
     }
 }
diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java
index fad6cd3..ebc2945 100644
--- a/core/java/android/app/compat/PackageOverride.java
+++ b/core/java/android/app/compat/PackageOverride.java
@@ -24,6 +24,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * An app compat override applied to a given package and change id pairing.
@@ -139,6 +140,22 @@
 
     /** @hide */
     @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PackageOverride that = (PackageOverride) o;
+        return mMinVersionCode == that.mMinVersionCode && mMaxVersionCode == that.mMaxVersionCode
+                && mEnabled == that.mEnabled;
+    }
+
+    /** @hide */
+    @Override
+    public int hashCode() {
+        return Objects.hash(mMinVersionCode, mMaxVersionCode, mEnabled);
+    }
+
+    /** @hide */
+    @Override
     public String toString() {
         if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
             return Boolean.toString(mEnabled);
diff --git a/core/java/android/app/usage/OWNERS b/core/java/android/app/usage/OWNERS
index a33d0ad..9668f80 100644
--- a/core/java/android/app/usage/OWNERS
+++ b/core/java/android/app/usage/OWNERS
@@ -3,3 +3,5 @@
 yamasani@google.com
 mwachens@google.com
 varunshah@google.com
+
+per-file *StorageStats* = file:/core/java/android/os/storage/OWNERS
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 5b72b76..a9ddefb 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3057,6 +3057,9 @@
         } else if (profile == BluetoothProfile.LE_AUDIO) {
             BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this);
             return true;
+        } else if (profile == BluetoothProfile.VOLUME_CONTROL) {
+            BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this);
+            return true;
         } else {
             return false;
         }
@@ -3149,6 +3152,11 @@
             case BluetoothProfile.LE_AUDIO:
                 BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy;
                 leAudio.close();
+                break;
+            case BluetoothProfile.VOLUME_CONTROL:
+                BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy;
+                vcs.close();
+                break;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index aea8210..2f771e9 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -1190,7 +1190,9 @@
                     characteristic.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
-            mDeviceBusy = false;
+            synchronized (mDeviceBusyLock) {
+                mDeviceBusy = false;
+            }
             return false;
         }
 
@@ -1226,7 +1228,9 @@
                     mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
-            mDeviceBusy = false;
+            synchronized (mDeviceBusyLock) {
+                mDeviceBusy = false;
+            }
             return false;
         }
 
@@ -1274,7 +1278,9 @@
                     AUTHENTICATION_NONE, characteristic.getValue(), mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
-            mDeviceBusy = false;
+            synchronized (mDeviceBusyLock) {
+                mDeviceBusy = false;
+            }
             return false;
         }
 
@@ -1317,7 +1323,9 @@
                     descriptor.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
-            mDeviceBusy = false;
+            synchronized (mDeviceBusyLock) {
+                mDeviceBusy = false;
+            }
             return false;
         }
 
@@ -1359,7 +1367,9 @@
                     AUTHENTICATION_NONE, descriptor.getValue(), mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
-            mDeviceBusy = false;
+            synchronized (mDeviceBusyLock) {
+                mDeviceBusy = false;
+            }
             return false;
         }
 
@@ -1428,7 +1438,9 @@
             mService.endReliableWrite(mClientIf, mDevice.getAddress(), true, mAttributionSource);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
-            mDeviceBusy = false;
+            synchronized (mDeviceBusyLock) {
+                mDeviceBusy = false;
+            }
             return false;
         }
 
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 9de27ff..c438dd3 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -356,7 +356,6 @@
      * earbud)
      * @param device LE Audio capable device
      * @return group id that this device currently belongs to
-     * @hide
      */
     @RequiresLegacyBluetoothPermission
     @RequiresBluetoothConnectPermission
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 161c843..83a272fc 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -208,17 +208,24 @@
     /**
      * LE Audio Device
      *
-     * @hide
      */
     int LE_AUDIO = 22;
 
     /**
+     * Volume Control profile
+     *
+     * @hide
+     */
+    @SystemApi
+    int VOLUME_CONTROL = 23;
+
+    /**
      * 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 = 22;
+    int MAX_PROFILE_ID = 23;
 
     /**
      * Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothVolumeControl.java b/core/java/android/bluetooth/BluetoothVolumeControl.java
new file mode 100644
index 0000000..678c11a
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothVolumeControl.java
@@ -0,0 +1,313 @@
+/*
+ * 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.Manifest;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Attributable;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.CloseGuard;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth Volume Control service.
+ *
+ * <p>BluetoothVolumeControl is a proxy object for controlling the Bluetooth VC
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothVolumeControl proxy object.
+ * @hide
+ */
+@SystemApi
+public final class BluetoothVolumeControl implements BluetoothProfile, AutoCloseable {
+    private static final String TAG = "BluetoothVolumeControl";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private CloseGuard mCloseGuard;
+
+    /**
+     * Intent used to broadcast the change in connection state of the Volume Control
+     * profile.
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+     * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     *
+     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SuppressLint("ActionValue")
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+            "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED";
+
+    private BluetoothAdapter mAdapter;
+    private final AttributionSource mAttributionSource;
+    private final BluetoothProfileConnector<IBluetoothVolumeControl> mProfileConnector =
+            new BluetoothProfileConnector(this, BluetoothProfile.VOLUME_CONTROL, TAG,
+                    IBluetoothVolumeControl.class.getName()) {
+                @Override
+                public IBluetoothVolumeControl getServiceInterface(IBinder service) {
+                    return IBluetoothVolumeControl.Stub.asInterface(Binder.allowBlocking(service));
+                }
+            };
+
+    /**
+     * Create a BluetoothVolumeControl proxy object for interacting with the local
+     * Bluetooth Volume Control service.
+     */
+    /*package*/ BluetoothVolumeControl(Context context, ServiceListener listener,
+            BluetoothAdapter adapter) {
+        mAdapter = adapter;
+        mAttributionSource = adapter.getAttributionSource();
+        mProfileConnector.connect(context, listener);
+        mCloseGuard = new CloseGuard();
+        mCloseGuard.open("close");
+    }
+
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    protected void finalize() {
+        if (mCloseGuard != null) {
+            mCloseGuard.warnIfOpen();
+        }
+        close();
+    }
+
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void close() {
+        mProfileConnector.disconnect();
+    }
+
+    private IBluetoothVolumeControl getService() { return mProfileConnector.getService(); }
+
+    /**
+     * Get the list of connected devices. Currently at most one.
+     *
+     * @return list of connected devices
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @NonNull List<BluetoothDevice> getConnectedDevices() {
+        if (DBG) log("getConnectedDevices()");
+        final IBluetoothVolumeControl service = getService();
+        if (service != null && isEnabled()) {
+            try {
+                return Attributable.setAttributionSource(
+                        service.getConnectedDevices(mAttributionSource), mAttributionSource);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (service == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get the list of devices matching specified states. Currently at most one.
+     *
+     * @return list of matching devices
+     *
+     * @hide
+     */
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) log("getDevicesMatchingStates()");
+        final IBluetoothVolumeControl service = getService();
+        if (service != null && isEnabled()) {
+            try {
+                return Attributable.setAttributionSource(
+                        service.getDevicesMatchingConnectionStates(states, mAttributionSource),
+                        mAttributionSource);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (service == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get connection state of device
+     *
+     * @return device connection state
+     *
+     * @hide
+     */
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) log("getConnectionState(" + device + ")");
+        final IBluetoothVolumeControl service = getService();
+        if (service != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return service.getConnectionState(device, mAttributionSource);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (service == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Tells remote device to set an absolute volume.
+     *
+     * @param volume Absolute volume to be set on remote device.
+     *               Minimum value is 0 and maximum value is 255
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public void setVolume(@Nullable BluetoothDevice device,
+            @IntRange(from = 0, to = 255) int volume) {
+        if (DBG)
+            log("setVolume(" + volume + ")");
+        final IBluetoothVolumeControl service = getService();
+        try {
+            if (service != null && isEnabled()) {
+                service.setVolume(device, volume, mAttributionSource);
+                return;
+            }
+            if (service == null)
+                Log.w(TAG, "Proxy not attached to service");
+        } catch (RemoteException e) {
+            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+        }
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+        final IBluetoothVolumeControl service = getService();
+        if (service != null && isEnabled() && isValidDevice(device)) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+                return false;
+            }
+            try {
+                return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (service == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresBluetoothConnectPermission
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.BLUETOOTH_CONNECT,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+    })
+    public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
+        final IBluetoothVolumeControl service = getService();
+        if (service != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return service.getConnectionPolicy(device, mAttributionSource);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            }
+        }
+        if (service == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+    }
+
+    private boolean isEnabled() {
+        return mAdapter.getState() == BluetoothAdapter.STATE_ON;
+    }
+
+    private static boolean isValidDevice(@Nullable BluetoothDevice device) {
+        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
+    }
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+}
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
index 4e5ede7..bb0b956 100644
--- a/core/java/android/bluetooth/OobData.java
+++ b/core/java/android/bluetooth/OobData.java
@@ -937,17 +937,18 @@
     }
 
     @NonNull
-    private String toHexString(@NonNull int b) {
+    private String toHexString(int b) {
         return toHexString(new byte[] {(byte) b});
     }
 
     @NonNull
-    private String toHexString(@NonNull byte b) {
+    private String toHexString(byte b) {
         return toHexString(new byte[] {b});
     }
 
     @NonNull
-    private String toHexString(@NonNull byte[] array) {
+    private String toHexString(byte[] array) {
+        if (array == null) return "null";
         StringBuilder builder = new StringBuilder(array.length * 2);
         for (byte b: array) {
             builder.append(String.format("%02x", b));
diff --git a/core/java/android/companion/Association.java b/core/java/android/companion/Association.java
index 9007d9d..b060ce2 100644
--- a/core/java/android/companion/Association.java
+++ b/core/java/android/companion/Association.java
@@ -53,8 +53,6 @@
 
 
 
-
-
     // Code below generated by codegen v1.0.22.
     //
     // DO NOT MODIFY!
@@ -242,7 +240,7 @@
     };
 
     @DataClass.Generated(
-            time = 1612832377589L,
+            time = 1611795283642L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/companion/Association.java",
             inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final  boolean mNotifyOnDeviceNearby\nprivate final  long mTimeApprovedMs\npublic  int getUserId()\nprivate  java.lang.String timeApprovedMsToString()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 688483a..19550de 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1805,7 +1805,7 @@
      * the package name of the current installed package to be uninstalled.
      * You can optionally supply {@link #EXTRA_RETURN_RESULT}.
      * <p>
-     * Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install
+     * Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the uninstall
      * succeeded.
      * <p>
      * Requires {@link android.Manifest.permission#REQUEST_DELETE_PACKAGES}
@@ -5033,7 +5033,7 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
     /**
-     * An activity to run when device is inserted into a car dock.
+     * An activity to run when device is inserted into a desk dock.
      * Used with {@link #ACTION_MAIN} to launch an activity.  For more
      * information, see {@link android.app.UiModeManager}.
      */
@@ -5253,6 +5253,30 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES";
 
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the weather application.
+     * The activity should be able to give the user information about the weather
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String)} to generate a main
+     * Intent with this category in the selector.</p>
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_WEATHER = "android.intent.category.APP_WEATHER";
+
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the fitness application.
+     * The activity should be able to give the user fitness information and manage workouts
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String)} to generate a main
+     * Intent with this category in the selector.</p>
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_FITNESS = "android.intent.category.APP_FITNESS";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard extra data keys.
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index a167cb3..8d3452e 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -597,7 +597,7 @@
      * which will evaluate the permission access based on the current fg/bg state of the
      * app and leave a record that the data was accessed.
      *
-     * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as
+     * <p>This API assumes the {@link Binder#getCallingUid()} is the same as
      * {@link Process#myUid()}.
      *
      * @param context Context for accessing resources.
@@ -634,7 +634,7 @@
      * listener you should use this method which will evaluate the permission access based
      * on the current fg/bg state of the app and leave a record that the data was accessed.
      *
-     * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as
+     * <p>This API assumes the {@link Binder#getCallingUid()} is the same as
      * {@link Process#myUid()}.
      *
      * @param context Context for accessing resources.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d3ed006..a4ff18a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -752,6 +752,9 @@
 
     void requestChecksums(in String packageName, boolean includeSplits, int optional, int required, in List trustedInstallers, in IOnChecksumsReadyListener onChecksumsReadyListener, int userId);
 
+    IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
+                String featureId, int userId);
+
     //------------------------------------------------------------------------
     //
     // The following binder interfaces have been moved to IPermissionManager
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2ed00b5..c2f3ef0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4470,12 +4470,17 @@
      * main activity in the category {@link Intent#CATEGORY_LAUNCHER}. Returns
      * <code>null</code> if neither are found.
      *
+     * <p>Consider using {@link #getLaunchIntentSenderForPackage(String)} if
+     * the caller is not allowed to query for the <code>packageName</code>.
+     *
      * @param packageName The name of the package to inspect.
      *
      * @return A fully-qualified {@link Intent} that can be used to launch the
      * main activity in the package. Returns <code>null</code> if the package
      * does not contain such an activity, or if <em>packageName</em> is not
      * recognized.
+     *
+     * @see #getLaunchIntentSenderForPackage(String)
      */
     public abstract @Nullable Intent getLaunchIntentForPackage(@NonNull String packageName);
 
@@ -4510,6 +4515,28 @@
     public abstract @Nullable Intent getCarLaunchIntentForPackage(@NonNull String packageName);
 
     /**
+     * Returns an {@link IntentSender} that can be used to launch a front-door activity in a
+     * package. This is used, for example, to implement an "open" button when browsing through
+     * packages. The current implementation is the same with
+     * {@link #getLaunchIntentForPackage(String)}. Instead of returning the {@link Intent}, it
+     * returns the {@link IntentSender} which is not restricted by the package visibility.
+     *
+     * <p>The caller can invoke
+     * {@link IntentSender#sendIntent(Context, int, Intent, IntentSender.OnFinished, Handler)}
+     * to launch the activity. An {@link IntentSender.SendIntentException} is thrown if the
+     * package does not contain such an activity, or if <em>packageName</em> is not recognized.
+     *
+     * @param packageName The name of the package to inspect.
+     * @return Returns a {@link IntentSender} to launch the activity.
+     *
+     * @see #getLaunchIntentForPackage(String)
+     */
+    public @NonNull IntentSender getLaunchIntentSenderForPackage(@NonNull String packageName) {
+        throw new UnsupportedOperationException("getLaunchIntentSenderForPackage not implemented"
+                + "in subclass");
+    }
+
+    /**
      * Return an array of all of the POSIX secondary group IDs that have been
      * assigned to the given package.
      * <p>
@@ -6798,7 +6825,7 @@
     @NonNull
     public Resources getResourcesForApplication(@NonNull ApplicationInfo app, @Nullable
             Configuration configuration) throws NameNotFoundException {
-        throw new UnsupportedOperationException();
+        return getResourcesForApplication(app);
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4ff2624..697b72a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -884,7 +884,11 @@
         if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
             if (p.mSigningDetails != SigningDetails.UNKNOWN) {
                 // only return a valid SigningInfo if there is signing information to report
-                pi.signingInfo = new SigningInfo(p.mSigningDetails);
+                pi.signingInfo = new SigningInfo(
+                        new android.content.pm.SigningDetails(p.mSigningDetails.signatures,
+                                p.mSigningDetails.signatureSchemeVersion,
+                                p.mSigningDetails.publicKeys,
+                                p.mSigningDetails.pastSigningCertificates));
             } else {
                 pi.signingInfo = null;
             }
@@ -1399,7 +1403,7 @@
             // must use v2 signing scheme
             minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
         }
-        SigningDetails verified;
+        final android.content.pm.SigningDetails verified;
         if (skipVerify) {
             // systemDir APKs are already trusted, save time by not verifying; since the signature
             // is not verified and some system apps can have their V2+ signatures stripped allow
@@ -1414,9 +1418,13 @@
         // we encountered. Note that for splits, certificates may have
         // already been populated during an earlier parse of a base APK.
         if (pkg.mSigningDetails == SigningDetails.UNKNOWN) {
-            pkg.mSigningDetails = verified;
+            pkg.mSigningDetails = new SigningDetails(verified.getSignatures(),
+                    verified.getSignatureSchemeVersion(),
+                    verified.getPublicKeys(),
+                    verified.getPastSigningCertificates());
         } else {
-            if (!Signature.areExactMatch(pkg.mSigningDetails.signatures, verified.signatures)) {
+            if (!Signature.areExactMatch(pkg.mSigningDetails.signatures,
+                    verified.getSignatures())) {
                 throw new PackageParserException(
                         INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                         apkPath + " has mismatched certificates");
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 691c69c..a5d97f9 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -211,6 +211,8 @@
      * Additional flag for {@link #protectionLevel}, corresponding to the
      * {@code documenter} value of {@link android.R.attr#protectionLevel}.
      *
+     * @deprecated this protectionLevel is obsolete. Permissions previously granted
+     * through this protectionLevel have been migrated to use <code>role</code> instead
      * @hide
      */
     @SystemApi
@@ -309,7 +311,6 @@
             PROTECTION_FLAG_OEM,
             PROTECTION_FLAG_VENDOR_PRIVILEGED,
             PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
-            PROTECTION_FLAG_DOCUMENTER,
             PROTECTION_FLAG_CONFIGURATOR,
             PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
             PROTECTION_FLAG_APP_PREDICTOR,
@@ -561,9 +562,6 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) {
             protLevel.append("|textClassifier");
         }
-        if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) {
-            protLevel.append("|documenter");
-        }
         if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) {
             protLevel.append("|configurator");
         }
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index bce4b87..3f5c5d2 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -256,7 +256,7 @@
         try {
             if (obj != null) {
                 Signature other = (Signature)obj;
-                // Note, some classes, such as PackageParser.SigningDetails, rely on equals
+                // Note, some classes, such as SigningDetails, rely on equals
                 // only comparing the mSignature arrays without the flags.
                 return this == other || Arrays.equals(mSignature, other.mSignature);
             }
diff --git a/core/java/android/content/pm/SigningDetails.java b/core/java/android/content/pm/SigningDetails.java
new file mode 100644
index 0000000..584a058
--- /dev/null
+++ b/core/java/android/content/pm/SigningDetails.java
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.PackageUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DataClass;
+
+import libcore.util.HexEncoding;
+
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A container for signing-related data of an application package.
+ *
+ * @hide
+ */
+@DataClass(genConstructor = false, genConstDefs = false, genParcelable = true, genAidl = false)
+public final class SigningDetails implements Parcelable {
+
+    private static final String TAG = "SigningDetails";
+
+    @IntDef({SignatureSchemeVersion.UNKNOWN,
+            SignatureSchemeVersion.JAR,
+            SignatureSchemeVersion.SIGNING_BLOCK_V2,
+            SignatureSchemeVersion.SIGNING_BLOCK_V3,
+            SignatureSchemeVersion.SIGNING_BLOCK_V4})
+    public @interface SignatureSchemeVersion {
+        int UNKNOWN = 0;
+        int JAR = 1;
+        int SIGNING_BLOCK_V2 = 2;
+        int SIGNING_BLOCK_V3 = 3;
+        int SIGNING_BLOCK_V4 = 4;
+    }
+
+    /** The signing certificates associated with this application package. */
+    private final @Nullable Signature[] mSignatures;
+
+    /** The signature scheme version for this application package. */
+    private final @SignatureSchemeVersion int mSignatureSchemeVersion;
+
+    /** The public keys set for the certificates. */
+    private final @Nullable ArraySet<PublicKey> mPublicKeys;
+
+    /**
+     * APK Signature Scheme v3 includes support for adding a proof-of-rotation record that
+     * contains two pieces of information:
+     *   1) the past signing certificates
+     *   2) the flags that APK wants to assign to each of the past signing certificates.
+     *
+     * This collection of {@code Signature} objects, each of which is formed from a former
+     * signing certificate of this APK before it was changed by signing certificate rotation,
+     * represents the first piece of information.  It is the APK saying to the rest of the
+     * world: "hey if you trust the old cert, you can trust me!"  This is useful, if for
+     * instance, the platform would like to determine whether or not to allow this APK to do
+     * something it would've allowed it to do under the old cert (like upgrade).
+     */
+    private final @Nullable Signature[] mPastSigningCertificates;
+
+    /** special value used to see if cert is in package - not exposed to callers */
+    private static final int PAST_CERT_EXISTS = 0;
+
+    @IntDef(flag = true,
+            value = {CertCapabilities.INSTALLED_DATA,
+                    CertCapabilities.SHARED_USER_ID,
+                    CertCapabilities.PERMISSION,
+                    CertCapabilities.ROLLBACK})
+    public @interface CertCapabilities {
+
+        /** accept data from already installed pkg with this cert */
+        int INSTALLED_DATA = 1;
+
+        /** accept sharedUserId with pkg with this cert */
+        int SHARED_USER_ID = 2;
+
+        /** grant SIGNATURE permissions to pkgs with this cert */
+        int PERMISSION = 4;
+
+        /** allow pkg to update to one signed by this certificate */
+        int ROLLBACK = 8;
+
+        /** allow pkg to continue to have auth access gated by this cert */
+        int AUTH = 16;
+    }
+
+    /** A representation of unknown signing details. Use instead of null. */
+    public static final SigningDetails UNKNOWN = new SigningDetails(/* signatures */ null,
+            SignatureSchemeVersion.UNKNOWN, /* keys */ null, /* pastSigningCertificates */ null);
+
+    @VisibleForTesting
+    public SigningDetails(@Nullable Signature[] signatures,
+            @SignatureSchemeVersion int signatureSchemeVersion,
+            @Nullable ArraySet<PublicKey> keys, @Nullable Signature[] pastSigningCertificates) {
+        mSignatures = signatures;
+        mSignatureSchemeVersion = signatureSchemeVersion;
+        mPublicKeys = keys;
+        mPastSigningCertificates = pastSigningCertificates;
+    }
+
+    public SigningDetails(@Nullable Signature[] signatures,
+            @SignatureSchemeVersion int signatureSchemeVersion,
+            @Nullable Signature[] pastSigningCertificates)
+            throws CertificateException {
+        this(signatures, signatureSchemeVersion, toSigningKeys(signatures),
+                pastSigningCertificates);
+    }
+
+    public SigningDetails(@Nullable Signature[] signatures,
+            @SignatureSchemeVersion int signatureSchemeVersion)
+            throws CertificateException {
+        this(signatures, signatureSchemeVersion, /* pastSigningCertificates */ null);
+    }
+
+    public SigningDetails(@Nullable SigningDetails orig) {
+        if (orig != null) {
+            if (orig.mSignatures != null) {
+                mSignatures = orig.mSignatures.clone();
+            } else {
+                mSignatures = null;
+            }
+            mSignatureSchemeVersion = orig.mSignatureSchemeVersion;
+            mPublicKeys = new ArraySet<>(orig.mPublicKeys);
+            if (orig.mPastSigningCertificates != null) {
+                mPastSigningCertificates = orig.mPastSigningCertificates.clone();
+            } else {
+                mPastSigningCertificates = null;
+            }
+        } else {
+            mSignatures = null;
+            mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN;
+            mPublicKeys = null;
+            mPastSigningCertificates = null;
+        }
+    }
+
+    /**
+     * Merges the signing lineage of this instance with the lineage in the provided {@code
+     * otherSigningDetails} when one has the same or an ancestor signer of the other.
+     *
+     * <p>Merging two signing lineages will result in a new {@code SigningDetails} instance
+     * containing the longest common lineage with the most restrictive capabilities. If the two
+     * lineages contain the same signers with the same capabilities then the instance on which
+     * this was invoked is returned without any changes. Similarly if neither instance has a
+     * lineage, or if neither has the same or an ancestor signer then this instance is returned.
+     *
+     * Following are some example results of this method for lineages with signers A, B, C, D:
+     * - lineage B merged with lineage A -> B returns lineage A -> B.
+     * - lineage A -> B merged with lineage B -> C returns lineage A -> B -> C
+     * - lineage A -> B with the {@code PERMISSION} capability revoked for A merged with
+     *  lineage A -> B with the {@code SHARED_USER_ID} capability revoked for A returns
+     *  lineage A -> B with both capabilities revoked for A.
+     * - lineage A -> B -> C merged with lineage A -> B -> D would return the original lineage
+     *  A -> B -> C since the current signer of both instances is not the same or in the
+     *   lineage of the other.
+     *
+     * @param otherSigningDetails The {@code SigningDetails} you would like to merge with.
+     * @return Merged {@code SigningDetails} instance when one has the same or an ancestor signer
+     *         of the other. If neither instance has a lineage, or if neither has the same or an
+     *         ancestor signer then this instance is returned.
+     */
+    public @NonNull SigningDetails mergeLineageWith(@NonNull SigningDetails otherSigningDetails) {
+        if (!hasPastSigningCertificates()) {
+            return otherSigningDetails.hasPastSigningCertificates()
+                    && otherSigningDetails.hasAncestorOrSelf(this) ? otherSigningDetails : this;
+        }
+        if (!otherSigningDetails.hasPastSigningCertificates()) {
+            return this;
+        }
+        // Use the utility method to determine which SigningDetails instance is the descendant
+        // and to confirm that the signing lineage does not diverge.
+        SigningDetails descendantSigningDetails = getDescendantOrSelf(otherSigningDetails);
+        if (descendantSigningDetails == null) {
+            return this;
+        }
+        return descendantSigningDetails == this ? mergeLineageWithAncestorOrSelf(
+                otherSigningDetails) : otherSigningDetails.mergeLineageWithAncestorOrSelf(this);
+    }
+
+    /**
+     * Merges the signing lineage of this instance with the lineage of the ancestor (or same)
+     * signer in the provided {@code otherSigningDetails}.
+     *
+     * @param otherSigningDetails The {@code SigningDetails} you would like to merge with.
+     * @return Merged {@code SigningDetails} instance.
+     */
+    private @NonNull SigningDetails mergeLineageWithAncestorOrSelf(
+            @NonNull SigningDetails otherSigningDetails) {
+        // This method should only be called with instances that contain lineages.
+        int index = mPastSigningCertificates.length - 1;
+        int otherIndex = otherSigningDetails.mPastSigningCertificates.length - 1;
+        if (index < 0 || otherIndex < 0) {
+            return this;
+        }
+
+        List<Signature> mergedSignatures = new ArrayList<>();
+        boolean capabilitiesModified = false;
+        // If this is a descendant lineage then add all of the descendant signer(s) to the
+        // merged lineage until the ancestor signer is reached.
+        while (index >= 0 && !mPastSigningCertificates[index].equals(
+                otherSigningDetails.mPastSigningCertificates[otherIndex])) {
+            mergedSignatures.add(new Signature(mPastSigningCertificates[index--]));
+        }
+        // If the signing lineage was exhausted then the provided ancestor is not actually an
+        // ancestor of this lineage.
+        if (index < 0) {
+            return this;
+        }
+
+        do {
+            // Add the common signer to the merged lineage with the most restrictive
+            // capabilities of the two lineages.
+            Signature signature = mPastSigningCertificates[index--];
+            Signature ancestorSignature =
+                    otherSigningDetails.mPastSigningCertificates[otherIndex--];
+            Signature mergedSignature = new Signature(signature);
+            int mergedCapabilities = signature.getFlags() & ancestorSignature.getFlags();
+            if (signature.getFlags() != mergedCapabilities) {
+                capabilitiesModified = true;
+                mergedSignature.setFlags(mergedCapabilities);
+            }
+            mergedSignatures.add(mergedSignature);
+        } while (index >= 0 && otherIndex >= 0 && mPastSigningCertificates[index].equals(
+                otherSigningDetails.mPastSigningCertificates[otherIndex]));
+
+        // If both lineages still have elements then their lineages have diverged; since this is
+        // not supported return the invoking instance.
+        if (index >= 0 && otherIndex >= 0) {
+            return this;
+        }
+
+        // Add any remaining elements from either lineage that is not yet exhausted to the
+        // the merged lineage.
+        while (otherIndex >= 0) {
+            mergedSignatures.add(new Signature(
+                    otherSigningDetails.mPastSigningCertificates[otherIndex--]));
+        }
+        while (index >= 0) {
+            mergedSignatures.add(new Signature(mPastSigningCertificates[index--]));
+        }
+
+        // if this lineage already contains all the elements in the ancestor and none of the
+        // capabilities were changed then just return this instance.
+        if (mergedSignatures.size() == mPastSigningCertificates.length
+                && !capabilitiesModified) {
+            return this;
+        }
+        // Since the signatures were added to the merged lineage from newest to oldest reverse
+        // the list to ensure the oldest signer is at index 0.
+        Collections.reverse(mergedSignatures);
+        try {
+            return new SigningDetails(new Signature[]{new Signature(mSignatures[0])},
+                    mSignatureSchemeVersion, mergedSignatures.toArray(new Signature[0]));
+        } catch (CertificateException e) {
+            Slog.e(TAG, "Caught an exception creating the merged lineage: ", e);
+            return this;
+        }
+    }
+
+    /**
+     * Returns whether this and the provided {@code otherSigningDetails} share a common
+     * ancestor.
+     *
+     * <p>The two SigningDetails have a common ancestor if any of the following conditions are
+     * met:
+     * - If neither has a lineage and their current signer(s) are equal.
+     * - If only one has a lineage and the signer of the other is the same or in the lineage.
+     * - If both have a lineage and their current signers are the same or one is in the lineage
+     * of the other, and their lineages do not diverge to different signers.
+     */
+    public boolean hasCommonAncestor(@NonNull SigningDetails otherSigningDetails) {
+        if (!hasPastSigningCertificates()) {
+            // If this instance does not have a lineage then it must either be in the ancestry
+            // of or the same signer of the otherSigningDetails.
+            return otherSigningDetails.hasAncestorOrSelf(this);
+        }
+        if (!otherSigningDetails.hasPastSigningCertificates()) {
+            return hasAncestorOrSelf(otherSigningDetails);
+        }
+        // If both have a lineage then use getDescendantOrSelf to obtain the descendant signing
+        // details; a null return from that method indicates there is no common lineage between
+        // the two or that they diverge at a point in the lineage.
+        return getDescendantOrSelf(otherSigningDetails) != null;
+    }
+
+    /**
+     * Returns whether this instance is currently signed, or has ever been signed, with a
+     * signing certificate from the provided {@link Set} of {@code certDigests}.
+     *
+     * <p>The provided {@code certDigests} should contain the SHA-256 digest of the DER encoding
+     * of each trusted certificate with the digest characters in upper case. If this instance
+     * has multiple signers then all signers must be in the provided {@code Set}. If this
+     * instance has a signing lineage then this method will return true if any of the previous
+     * signers in the lineage match one of the entries in the {@code Set}.
+     */
+    public boolean hasAncestorOrSelfWithDigest(@Nullable Set<String> certDigests) {
+        if (this == UNKNOWN || certDigests == null || certDigests.size() == 0) {
+            return false;
+        }
+        // If an app is signed by multiple signers then all of the signers must be in the Set.
+        if (mSignatures.length > 1) {
+            // If the Set has less elements than the number of signatures then immediately
+            // return false as there's no way to satisfy the requirement of all signatures being
+            // in the Set.
+            if (certDigests.size() < mSignatures.length) {
+                return false;
+            }
+            for (Signature signature : mSignatures) {
+                String signatureDigest = PackageUtils.computeSha256Digest(
+                        signature.toByteArray());
+                if (!certDigests.contains(signatureDigest)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        String signatureDigest = PackageUtils.computeSha256Digest(mSignatures[0].toByteArray());
+        if (certDigests.contains(signatureDigest)) {
+            return true;
+        }
+        if (hasPastSigningCertificates()) {
+            // The last element in the pastSigningCertificates array is the current signer;
+            // since that was verified above just check all the signers in the lineage.
+            for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
+                signatureDigest = PackageUtils.computeSha256Digest(
+                        mPastSigningCertificates[i].toByteArray());
+                if (certDigests.contains(signatureDigest)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the SigningDetails with a descendant (or same) signer after verifying the
+     * descendant has the same, a superset, or a subset of the lineage of the ancestor.
+     *
+     * <p>If this instance and the provided {@code otherSigningDetails} do not share an
+     * ancestry, or if their lineages diverge then null is returned to indicate there is no
+     * valid descendant SigningDetails.
+     */
+    private @Nullable SigningDetails getDescendantOrSelf(
+            @NonNull SigningDetails otherSigningDetails) {
+        final SigningDetails descendantSigningDetails;
+        final SigningDetails ancestorSigningDetails;
+        if (hasAncestorOrSelf(otherSigningDetails)) {
+            // If the otherSigningDetails has the same signer or a signer in the lineage of this
+            // instance then treat this instance as the descendant.
+            descendantSigningDetails = this;
+            ancestorSigningDetails = otherSigningDetails;
+        } else if (otherSigningDetails.hasAncestor(this)) {
+            // The above check confirmed that the two instances do not have the same signer and
+            // the signer of otherSigningDetails is not in this instance's lineage; if this
+            // signer is in the otherSigningDetails lineage then treat this as the ancestor.
+            descendantSigningDetails = otherSigningDetails;
+            ancestorSigningDetails = this;
+        } else {
+            // The signers are not the same and neither has the current signer of the other in
+            // its lineage; return null to indicate there is no descendant signer.
+            return null;
+        }
+        // Once the descent (or same) signer is identified iterate through the ancestry until
+        // the current signer of the ancestor is found.
+        int descendantIndex = descendantSigningDetails.mPastSigningCertificates.length - 1;
+        int ancestorIndex = ancestorSigningDetails.mPastSigningCertificates.length - 1;
+        while (descendantIndex >= 0
+                && !descendantSigningDetails.mPastSigningCertificates[descendantIndex].equals(
+                ancestorSigningDetails.mPastSigningCertificates[ancestorIndex])) {
+            descendantIndex--;
+        }
+        // Since the ancestry was verified above the descendant lineage should never be
+        // exhausted, but if for some reason the ancestor signer is not found then return null.
+        if (descendantIndex < 0) {
+            return null;
+        }
+        // Once the common ancestor (or same) signer is found iterate over the lineage of both
+        // to ensure that they are either the same or one is a subset of the other.
+        do {
+            descendantIndex--;
+            ancestorIndex--;
+        } while (descendantIndex >= 0 && ancestorIndex >= 0
+                && descendantSigningDetails.mPastSigningCertificates[descendantIndex].equals(
+                ancestorSigningDetails.mPastSigningCertificates[ancestorIndex]));
+
+        // If both lineages still have elements then they diverge and cannot be considered a
+        // valid common lineage.
+        if (descendantIndex >= 0 && ancestorIndex >= 0) {
+            return null;
+        }
+        // Since one or both of the lineages was exhausted they are either the same or one is a
+        // subset of the other; return the valid descendant.
+        return descendantSigningDetails;
+    }
+
+    /** Returns true if the signing details have one or more signatures. */
+    public boolean hasSignatures() {
+        return mSignatures != null && mSignatures.length > 0;
+    }
+
+    /** Returns true if the signing details have past signing certificates. */
+    public boolean hasPastSigningCertificates() {
+        return mPastSigningCertificates != null && mPastSigningCertificates.length > 0;
+    }
+
+    /**
+     * Determines if the provided {@code oldDetails} is an ancestor of or the same as this one.
+     * If the {@code oldDetails} signing certificate appears in our pastSigningCertificates,
+     * then that means it has authorized a signing certificate rotation, which eventually leads
+     * to our certificate, and thus can be trusted. If this method evaluates to true, this
+     * SigningDetails object should be trusted if the previous one is.
+     */
+    public boolean hasAncestorOrSelf(@NonNull SigningDetails oldDetails) {
+        if (this == UNKNOWN || oldDetails == UNKNOWN) {
+            return false;
+        }
+        if (oldDetails.mSignatures.length > 1) {
+            // multiple-signer packages cannot rotate signing certs, so we just compare current
+            // signers for an exact match
+            return signaturesMatchExactly(oldDetails);
+        } else {
+            // we may have signing certificate rotation history, check to see if the oldDetails
+            // was one of our old signing certificates
+            return hasCertificate(oldDetails.mSignatures[0]);
+        }
+    }
+
+    /**
+     * Similar to {@code hasAncestorOrSelf}. Returns true only if this {@code SigningDetails}
+     * is a descendant of {@code oldDetails}, not if they're the same. This is used to
+     * determine if this object is newer than the provided one.
+     */
+    public boolean hasAncestor(@NonNull SigningDetails oldDetails) {
+        if (this == UNKNOWN || oldDetails == UNKNOWN) {
+            return false;
+        }
+        if (hasPastSigningCertificates() && oldDetails.mSignatures.length == 1) {
+            // the last entry in pastSigningCertificates is the current signer, ignore it
+            for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
+                if (mPastSigningCertificates[i].equals(oldDetails.mSignatures[0])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether this {@code SigningDetails} has a signer in common with the provided
+     * {@code otherDetails} with the specified {@code flags} capabilities provided by this
+     * signer.
+     *
+     * <p>Note this method allows for the signing lineage to diverge, so this should only be
+     * used for instances where the only requirement is a common signer in the lineage with
+     * the specified capabilities. If the current signer of this instance is an ancestor of
+     * {@code otherDetails} then {@code true} is immediately returned since the current signer
+     * has all capabilities granted.
+     */
+    public boolean hasCommonSignerWithCapability(@NonNull SigningDetails otherDetails,
+            @CertCapabilities int flags) {
+        if (this == UNKNOWN || otherDetails == UNKNOWN) {
+            return false;
+        }
+        // If either is signed with more than one signer then both must be signed by the same
+        // signers to consider the capabilities granted.
+        if (mSignatures.length > 1 || otherDetails.mSignatures.length > 1) {
+            return signaturesMatchExactly(otherDetails);
+        }
+        // The Signature class does not use the granted capabilities in the hashCode
+        // computation, so a Set can be used to check for a common signer.
+        Set<Signature> otherSignatures = new ArraySet<>();
+        if (otherDetails.hasPastSigningCertificates()) {
+            otherSignatures.addAll(Arrays.asList(otherDetails.mPastSigningCertificates));
+        } else {
+            otherSignatures.addAll(Arrays.asList(otherDetails.mSignatures));
+        }
+        // If the current signer of this instance is an ancestor of the other than return true
+        // since all capabilities are granted to the current signer.
+        if (otherSignatures.contains(mSignatures[0])) {
+            return true;
+        }
+        if (hasPastSigningCertificates()) {
+            // Since the current signer was checked above and the last signature in the
+            // pastSigningCertificates is the current signer skip checking the last element.
+            for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
+                if (otherSignatures.contains(mPastSigningCertificates[i])) {
+                    // If the caller specified multiple capabilities ensure all are set.
+                    if ((mPastSigningCertificates[i].getFlags() & flags) == flags) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines if the provided {@code oldDetails} is an ancestor of this one, and whether or
+     * not this one grants it the provided capability, represented by the {@code flags}
+     * parameter.  In the event of signing certificate rotation, a package may still interact
+     * with entities signed by its old signing certificate and not want to break previously
+     * functioning behavior.  The {@code flags} value determines which capabilities the app
+     * signed by the newer signing certificate would like to continue to give to its previous
+     * signing certificate(s).
+     */
+    public boolean checkCapability(@NonNull SigningDetails oldDetails,
+            @CertCapabilities int flags) {
+        if (this == UNKNOWN || oldDetails == UNKNOWN) {
+            return false;
+        }
+        if (oldDetails.mSignatures.length > 1) {
+            // multiple-signer packages cannot rotate signing certs, so we must have an exact
+            // match, which also means all capabilities are granted
+            return signaturesMatchExactly(oldDetails);
+        } else {
+            // we may have signing certificate rotation history, check to see if the oldDetails
+            // was one of our old signing certificates, and if we grant it the capability it's
+            // requesting
+            return hasCertificate(oldDetails.mSignatures[0], flags);
+        }
+    }
+
+    /**
+     * A special case of {@code checkCapability} which re-encodes both sets of signing
+     * certificates to counteract a previous re-encoding.
+     */
+    public boolean checkCapabilityRecover(@NonNull SigningDetails oldDetails,
+            @CertCapabilities int flags) throws CertificateException {
+        if (oldDetails == UNKNOWN || this == UNKNOWN) {
+            return false;
+        }
+        if (hasPastSigningCertificates() && oldDetails.mSignatures.length == 1) {
+            // signing certificates may have rotated, check entire history for effective match
+            for (int i = 0; i < mPastSigningCertificates.length; i++) {
+                if (Signature.areEffectiveMatch(
+                        oldDetails.mSignatures[0],
+                        mPastSigningCertificates[i])
+                        && mPastSigningCertificates[i].getFlags() == flags) {
+                    return true;
+                }
+            }
+        } else {
+            return Signature.areEffectiveMatch(oldDetails.mSignatures, mSignatures);
+        }
+        return false;
+    }
+
+    /**
+     * Determine if {@code signature} is in this SigningDetails' signing certificate history,
+     * including the current signer.  Automatically returns false if this object has multiple
+     * signing certificates, since rotation is only supported for single-signers; this is
+     * enforced by {@code hasCertificateInternal}.
+     */
+    public boolean hasCertificate(@NonNull Signature signature) {
+        return hasCertificateInternal(signature, PAST_CERT_EXISTS);
+    }
+
+    /**
+     * Determine if {@code signature} is in this SigningDetails' signing certificate history,
+     * including the current signer, and whether or not it has the given permission.
+     * Certificates which match our current signer automatically get all capabilities.
+     * Automatically returns false if this object has multiple signing certificates, since
+     * rotation is only supported for single-signers.
+     */
+    public boolean hasCertificate(@NonNull Signature signature, @CertCapabilities int flags) {
+        return hasCertificateInternal(signature, flags);
+    }
+
+    /** Convenient wrapper for calling {@code hasCertificate} with certificate's raw bytes. */
+    public boolean hasCertificate(byte[] certificate) {
+        Signature signature = new Signature(certificate);
+        return hasCertificate(signature);
+    }
+
+    private boolean hasCertificateInternal(@NonNull Signature signature, int flags) {
+        if (this == UNKNOWN) {
+            return false;
+        }
+
+        // only single-signed apps can have pastSigningCertificates
+        if (hasPastSigningCertificates()) {
+            // check all past certs, except for the current one, which automatically gets all
+            // capabilities, since it is the same as the current signature
+            for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
+                if (mPastSigningCertificates[i].equals(signature)) {
+                    if (flags == PAST_CERT_EXISTS
+                            || (flags & mPastSigningCertificates[i].getFlags()) == flags) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        // not in previous certs signing history, just check the current signer and make sure
+        // we are singly-signed
+        return mSignatures.length == 1 && mSignatures[0].equals(signature);
+    }
+
+    /**
+     * Determines if the provided {@code sha256String} is an ancestor of this one, and whether
+     * or not this one grants it the provided capability, represented by the {@code flags}
+     * parameter.  In the event of signing certificate rotation, a package may still interact
+     * with entities signed by its old signing certificate and not want to break previously
+     * functioning behavior.  The {@code flags} value determines which capabilities the app
+     * signed by the newer signing certificate would like to continue to give to its previous
+     * signing certificate(s).
+     *
+     * @param sha256String A hex-encoded representation of a sha256 digest. In the case of an
+     *                     app with multiple signers, this represents the hex-encoded sha256
+     *                     digest of the combined hex-encoded sha256 digests of each individual
+     *                     signing certificate according to {@link
+     *                     PackageUtils#computeSignaturesSha256Digest(Signature[])}
+     */
+    public boolean checkCapability(@Nullable String sha256String, @CertCapabilities int flags) {
+        if (this == UNKNOWN || TextUtils.isEmpty(sha256String)) {
+            return false;
+        }
+
+        // first see if the hash represents a single-signer in our signing history
+        final byte[] sha256Bytes = HexEncoding.decode(sha256String, false /* allowSingleChar */);
+        if (hasSha256Certificate(sha256Bytes, flags)) {
+            return true;
+        }
+
+        // Not in signing history, either represents multiple signatures or not a match.
+        // Multiple signers can't rotate, so no need to check flags, just see if the SHAs match.
+        // We already check the single-signer case above as part of hasSha256Certificate, so no
+        // need to verify we have multiple signers, just run the old check
+        // just consider current signing certs
+        final String[] mSignaturesSha256Digests =
+                PackageUtils.computeSignaturesSha256Digests(mSignatures);
+        final String mSignaturesSha256Digest =
+                PackageUtils.computeSignaturesSha256Digest(mSignaturesSha256Digests);
+        return mSignaturesSha256Digest.equals(sha256String);
+    }
+
+    /**
+     * Determine if the {@code sha256Certificate} is in this SigningDetails' signing certificate
+     * history, including the current signer.  Automatically returns false if this object has
+     * multiple signing certificates, since rotation is only supported for single-signers.
+     */
+    public boolean hasSha256Certificate(byte[] sha256Certificate) {
+        return hasSha256CertificateInternal(sha256Certificate, PAST_CERT_EXISTS);
+    }
+
+    /**
+     * Determine if the {@code sha256Certificate} certificate hash corresponds to a signing
+     * certificate in this SigningDetails' signing certificate history, including the current
+     * signer, and whether or not it has the given permission.  Certificates which match our
+     * current signer automatically get all capabilities. Automatically returns false if this
+     * object has multiple signing certificates, since rotation is only supported for
+     * single-signers.
+     */
+    public boolean hasSha256Certificate(byte[] sha256Certificate, @CertCapabilities int flags) {
+        return hasSha256CertificateInternal(sha256Certificate, flags);
+    }
+
+    private boolean hasSha256CertificateInternal(byte[] sha256Certificate, int flags) {
+        if (this == UNKNOWN) {
+            return false;
+        }
+        if (hasPastSigningCertificates()) {
+            // check all past certs, except for the last one, which automatically gets all
+            // capabilities, since it is the same as the current signature, and is checked below
+            for (int i = 0; i < mPastSigningCertificates.length - 1; i++) {
+                byte[] digest = PackageUtils.computeSha256DigestBytes(
+                        mPastSigningCertificates[i].toByteArray());
+                if (Arrays.equals(sha256Certificate, digest)) {
+                    if (flags == PAST_CERT_EXISTS
+                            || (flags & mPastSigningCertificates[i].getFlags()) == flags) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        // not in previous certs signing history, just check the current signer
+        if (mSignatures.length == 1) {
+            byte[] digest = PackageUtils.computeSha256DigestBytes(mSignatures[0].toByteArray());
+            return Arrays.equals(sha256Certificate, digest);
+        }
+        return false;
+    }
+
+    /** Returns true if the signatures in this and other match exactly. */
+    public boolean signaturesMatchExactly(@NonNull SigningDetails other) {
+        return Signature.areExactMatch(mSignatures, other.mSignatures);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        boolean isUnknown = UNKNOWN == this;
+        dest.writeBoolean(isUnknown);
+        if (isUnknown) {
+            return;
+        }
+        dest.writeTypedArray(mSignatures, flags);
+        dest.writeInt(mSignatureSchemeVersion);
+        dest.writeArraySet(mPublicKeys);
+        dest.writeTypedArray(mPastSigningCertificates, flags);
+    }
+
+    protected SigningDetails(@NonNull Parcel in) {
+        final ClassLoader boot = Object.class.getClassLoader();
+        mSignatures = in.createTypedArray(Signature.CREATOR);
+        mSignatureSchemeVersion = in.readInt();
+        mPublicKeys = (ArraySet<PublicKey>) in.readArraySet(boot);
+        mPastSigningCertificates = in.createTypedArray(Signature.CREATOR);
+    }
+
+    public static final @NonNull Parcelable.Creator<SigningDetails> CREATOR =
+            new Creator<SigningDetails>() {
+                @Override
+                public SigningDetails createFromParcel(@NonNull Parcel source) {
+                    if (source.readBoolean()) {
+                        return UNKNOWN;
+                    }
+                    return new SigningDetails(source);
+                }
+
+                @Override
+                public SigningDetails[] newArray(int size) {
+                    return new SigningDetails[size];
+                }
+            };
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SigningDetails)) return false;
+
+        final SigningDetails that = (SigningDetails) o;
+
+        if (mSignatureSchemeVersion != that.mSignatureSchemeVersion) return false;
+        if (!Signature.areExactMatch(mSignatures, that.mSignatures)) return false;
+        if (mPublicKeys != null) {
+            if (!mPublicKeys.equals((that.mPublicKeys))) {
+                return false;
+            }
+        } else if (that.mPublicKeys != null) {
+            return false;
+        }
+
+        // can't use Signature.areExactMatch() because order matters with the past signing certs
+        if (!Arrays.equals(mPastSigningCertificates, that.mPastSigningCertificates)) {
+            return false;
+        }
+        // The capabilities for the past signing certs must match as well.
+        for (int i = 0; i < mPastSigningCertificates.length; i++) {
+            if (mPastSigningCertificates[i].getFlags()
+                    != that.mPastSigningCertificates[i].getFlags()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = +Arrays.hashCode(mSignatures);
+        result = 31 * result + mSignatureSchemeVersion;
+        result = 31 * result + (mPublicKeys != null ? mPublicKeys.hashCode() : 0);
+        result = 31 * result + Arrays.hashCode(mPastSigningCertificates);
+        return result;
+    }
+
+    /**
+     * Builder of {@code SigningDetails} instances.
+     */
+    public static class Builder {
+        private @NonNull Signature[] mSignatures;
+        private @SignatureSchemeVersion int mSignatureSchemeVersion =
+                SignatureSchemeVersion.UNKNOWN;
+        private @Nullable Signature[] mPastSigningCertificates;
+
+        public Builder() {
+        }
+
+        /** get signing certificates used to sign the current APK */
+        public SigningDetails.Builder setSignatures(@NonNull Signature[] signatures) {
+            mSignatures = signatures;
+            return this;
+        }
+
+        /** set the signature scheme version used to sign the APK */
+        public SigningDetails.Builder setSignatureSchemeVersion(
+                @SignatureSchemeVersion int signatureSchemeVersion) {
+            mSignatureSchemeVersion = signatureSchemeVersion;
+            return this;
+        }
+
+        /** set the signing certificates by which the APK proved it can be authenticated */
+        public SigningDetails.Builder setPastSigningCertificates(
+                @Nullable Signature[] pastSigningCertificates) {
+            mPastSigningCertificates = pastSigningCertificates;
+            return this;
+        }
+
+        private void checkInvariants() {
+            // must have signatures and scheme version set
+            if (mSignatures == null) {
+                throw new IllegalStateException("SigningDetails requires the current signing"
+                        + " certificates.");
+            }
+        }
+        /** build a {@code SigningDetails} object */
+        public SigningDetails build()
+                throws CertificateException {
+            checkInvariants();
+            return new SigningDetails(mSignatures, mSignatureSchemeVersion,
+                    mPastSigningCertificates);
+        }
+    }
+
+    /** Parses the public keys from the set of signatures. */
+    public static ArraySet<PublicKey> toSigningKeys(@NonNull Signature[] signatures)
+            throws CertificateException {
+        final ArraySet<PublicKey> keys = new ArraySet<>(signatures.length);
+        for (int i = 0; i < signatures.length; i++) {
+            keys.add(signatures[i].getPublicKey());
+        }
+        return keys;
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/SigningDetails.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * The signing certificates associated with this application package.
+     */
+    @DataClass.Generated.Member
+    public @Nullable Signature[] getSignatures() {
+        return mSignatures;
+    }
+
+    /**
+     * The signature scheme version for this application package.
+     */
+    @DataClass.Generated.Member
+    public @SignatureSchemeVersion int getSignatureSchemeVersion() {
+        return mSignatureSchemeVersion;
+    }
+
+    /**
+     * The public keys set for the certificates.
+     */
+    @DataClass.Generated.Member
+    public @Nullable ArraySet<PublicKey> getPublicKeys() {
+        return mPublicKeys;
+    }
+
+    /**
+     * APK Signature Scheme v3 includes support for adding a proof-of-rotation record that
+     * contains two pieces of information:
+     *   1) the past signing certificates
+     *   2) the flags that APK wants to assign to each of the past signing certificates.
+     *
+     * This collection of {@code Signature} objects, each of which is formed from a former
+     * signing certificate of this APK before it was changed by signing certificate rotation,
+     * represents the first piece of information.  It is the APK saying to the rest of the
+     * world: "hey if you trust the old cert, you can trust me!"  This is useful, if for
+     * instance, the platform would like to determine whether or not to allow this APK to do
+     * something it would've allowed it to do under the old cert (like upgrade).
+     */
+    @DataClass.Generated.Member
+    public @Nullable Signature[] getPastSigningCertificates() {
+        return mPastSigningCertificates;
+    }
+
+    @DataClass.Generated(
+            time = 1616984092921L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/content/pm/SigningDetails.java",
+            inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mSignatures\nprivate final @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate final @android.annotation.Nullable android.util.ArraySet<java.security.PublicKey> mPublicKeys\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\nprivate static final  int PAST_CERT_EXISTS\npublic static final  android.content.pm.SigningDetails UNKNOWN\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.SigningDetails> CREATOR\npublic @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWith(android.content.pm.SigningDetails)\nprivate @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWithAncestorOrSelf(android.content.pm.SigningDetails)\npublic  boolean hasCommonAncestor(android.content.pm.SigningDetails)\npublic  boolean hasAncestorOrSelfWithDigest(java.util.Set<java.lang.String>)\nprivate @android.annotation.Nullable android.content.pm.SigningDetails getDescendantOrSelf(android.content.pm.SigningDetails)\npublic  boolean hasSignatures()\npublic  boolean hasPastSigningCertificates()\npublic  boolean hasAncestorOrSelf(android.content.pm.SigningDetails)\npublic  boolean hasAncestor(android.content.pm.SigningDetails)\npublic  boolean hasCommonSignerWithCapability(android.content.pm.SigningDetails,int)\npublic  boolean checkCapability(android.content.pm.SigningDetails,int)\npublic  boolean checkCapabilityRecover(android.content.pm.SigningDetails,int)\npublic  boolean hasCertificate(android.content.pm.Signature)\npublic  boolean hasCertificate(android.content.pm.Signature,int)\npublic  boolean hasCertificate(byte[])\nprivate  boolean hasCertificateInternal(android.content.pm.Signature,int)\npublic  boolean checkCapability(java.lang.String,int)\npublic  boolean hasSha256Certificate(byte[])\npublic  boolean hasSha256Certificate(byte[],int)\nprivate  boolean hasSha256CertificateInternal(byte[],int)\npublic  boolean signaturesMatchExactly(android.content.pm.SigningDetails)\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override int hashCode()\npublic static  android.util.ArraySet<java.security.PublicKey> toSigningKeys(android.content.pm.Signature[])\nclass SigningDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.NonNull android.content.pm.Signature[] mSignatures\nprivate @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\npublic  android.content.pm.SigningDetails.Builder setSignatures(android.content.pm.Signature[])\npublic  android.content.pm.SigningDetails.Builder setSignatureSchemeVersion(int)\npublic  android.content.pm.SigningDetails.Builder setPastSigningCertificates(android.content.pm.Signature[])\nprivate  void checkInvariants()\npublic  android.content.pm.SigningDetails build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false, genParcelable=true, genAidl=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/SigningInfo.java b/core/java/android/content/pm/SigningInfo.java
index d14be9c..7459a90 100644
--- a/core/java/android/content/pm/SigningInfo.java
+++ b/core/java/android/content/pm/SigningInfo.java
@@ -16,7 +16,6 @@
 
 package android.content.pm;
 
-
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -27,25 +26,25 @@
 public final class SigningInfo implements Parcelable {
 
     @NonNull
-    private final PackageParser.SigningDetails mSigningDetails;
+    private final SigningDetails mSigningDetails;
 
     public SigningInfo() {
-        mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
+        mSigningDetails = SigningDetails.UNKNOWN;
     }
 
     /**
      * @hide only packagemanager should be populating this
      */
-    public SigningInfo(PackageParser.SigningDetails signingDetails) {
-        mSigningDetails = new PackageParser.SigningDetails(signingDetails);
+    public SigningInfo(SigningDetails signingDetails) {
+        mSigningDetails = new SigningDetails(signingDetails);
     }
 
     public SigningInfo(SigningInfo orig) {
-        mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails);
+        mSigningDetails = new SigningDetails(orig.mSigningDetails);
     }
 
     private SigningInfo(Parcel source) {
-        mSigningDetails = PackageParser.SigningDetails.CREATOR.createFromParcel(source);
+        mSigningDetails = SigningDetails.CREATOR.createFromParcel(source);
     }
 
     /**
@@ -53,7 +52,8 @@
      * their identity is viewed as being the set of all signers, not just any one.
      */
     public boolean hasMultipleSigners() {
-        return mSigningDetails.signatures != null && mSigningDetails.signatures.length > 1;
+        return mSigningDetails.getSignatures() != null
+                && mSigningDetails.getSignatures().length > 1;
     }
 
     /**
@@ -65,8 +65,8 @@
      * signing history, since it could change to a new signing certificate at any time.
      */
     public boolean hasPastSigningCertificates() {
-        return mSigningDetails.signatures != null
-                && mSigningDetails.pastSigningCertificates != null;
+        return mSigningDetails.getPastSigningCertificates() != null
+                && mSigningDetails.getPastSigningCertificates().length > 0;
     }
 
     /**
@@ -93,11 +93,11 @@
         } else if (!hasPastSigningCertificates()) {
 
             // this package is only signed by one signer with no history, return it
-            return mSigningDetails.signatures;
+            return mSigningDetails.getSignatures();
         } else {
 
             // this package has provided proof of past signing certificates, include them
-            return mSigningDetails.pastSigningCertificates;
+            return mSigningDetails.getPastSigningCertificates();
         }
     }
 
@@ -111,7 +111,7 @@
      * </note>
      */
     public Signature[] getApkContentsSigners() {
-        return mSigningDetails.signatures;
+        return mSigningDetails.getSignatures();
     }
 
     @Override
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index d8ec512..024c18c 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 
 import com.android.internal.util.DataClass;
@@ -398,10 +398,10 @@
     }
 
     @DataClass.Generated(
-            time = 1610596637723L,
+            time = 1616985847981L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.PackageParser.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final  int mRollbackDataPolicy\npublic  long getLongVersionCode()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final  int mRollbackDataPolicy\npublic  long getLongVersionCode()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 154d923..01c0a88 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseResult;
@@ -301,16 +302,15 @@
 
             parser = apkAssets.openXml(ParsingPackageUtils.ANDROID_MANIFEST_FILENAME);
 
-            final PackageParser.SigningDetails signingDetails;
+            final SigningDetails signingDetails;
             if ((flags & ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES) != 0) {
                 final boolean skipVerify = (flags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
                 try {
-                    ParseResult<PackageParser.SigningDetails> result =
-                            ParsingPackageUtils.getSigningDetails(input,
-                                    apkFile.getAbsolutePath(), skipVerify, false,
-                                    PackageParser.SigningDetails.UNKNOWN,
-                                    DEFAULT_TARGET_SDK_VERSION);
+                    final ParseResult<SigningDetails> result =
+                            ParsingPackageUtils.getSigningDetails(input, apkFile.getAbsolutePath(),
+                                    skipVerify, /* isStaticSharedLibrary */ false,
+                                    SigningDetails.UNKNOWN, DEFAULT_TARGET_SDK_VERSION);
                     if (result.isError()) {
                         return input.error(result);
                     }
@@ -319,7 +319,7 @@
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
             } else {
-                signingDetails = PackageParser.SigningDetails.UNKNOWN;
+                signingDetails = SigningDetails.UNKNOWN;
             }
 
             return parseApkLite(input, apkPath, parser, signingDetails);
@@ -340,7 +340,7 @@
     }
 
     private static ParseResult<ApkLite> parseApkLite(ParseInput input, String codePath,
-            XmlResourceParser parser, PackageParser.SigningDetails signingDetails)
+            XmlResourceParser parser, SigningDetails signingDetails)
             throws IOException, XmlPullParserException {
         ParseResult<Pair<String, String>> result = parsePackageSplitNames(input, parser);
         if (result.isError()) {
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index c9054fd..4ccd67d 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -32,7 +32,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
@@ -40,6 +39,7 @@
 import android.content.pm.SELinuxUtil;
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.component.ComponentParseUtils;
@@ -330,26 +330,26 @@
             pi.isApex = true;
         }
 
-        PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
+        final SigningDetails signingDetails = pkg.getSigningDetails();
         // deprecated method of getting signing certificates
         if ((flags & PackageManager.GET_SIGNATURES) != 0) {
             if (signingDetails.hasPastSigningCertificates()) {
                 // Package has included signing certificate rotation information.  Return the oldest
                 // cert so that programmatic checks keep working even if unaware of key rotation.
                 pi.signatures = new Signature[1];
-                pi.signatures[0] = signingDetails.pastSigningCertificates[0];
+                pi.signatures[0] = signingDetails.getPastSigningCertificates()[0];
             } else if (signingDetails.hasSignatures()) {
                 // otherwise keep old behavior
-                int numberOfSigs = signingDetails.signatures.length;
+                int numberOfSigs = signingDetails.getSignatures().length;
                 pi.signatures = new Signature[numberOfSigs];
-                System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
+                System.arraycopy(signingDetails.getSignatures(), 0, pi.signatures, 0,
                         numberOfSigs);
             }
         }
 
         // replacement for GET_SIGNATURES
         if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
-            if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+            if (signingDetails != SigningDetails.UNKNOWN) {
                 // only return a valid SigningInfo if there is signing information to report
                 pi.signingInfo = new SigningInfo(signingDetails);
             } else {
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index ed68dbf..72cc929 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -25,7 +25,7 @@
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageParser;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -320,7 +320,7 @@
 
     ParsingPackage setSharedUserLabel(int sharedUserLabel);
 
-    ParsingPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+    ParsingPackage setSigningDetails(SigningDetails signingDetails);
 
     ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName);
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 5a7f210..34a57f3 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -32,7 +32,7 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageParser;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedComponent;
@@ -292,7 +292,7 @@
     @DataClass.ParcelWith(ForInternedString.class)
     protected String volumeUuid;
     @Nullable
-    private PackageParser.SigningDetails signingDetails;
+    private SigningDetails signingDetails;
 
     @NonNull
     @DataClass.ParcelWith(ForInternedString.class)
@@ -723,6 +723,7 @@
 
     @Override
     public ParsingPackageImpl addImplicitPermission(String permission) {
+        addUsesPermission(new ParsedUsesPermission(permission, 0 /*usesPermissionFlags*/));
         this.implicitPermissions = CollectionUtils.add(this.implicitPermissions,
                 TextUtils.safeIntern(permission));
         return this;
@@ -1714,7 +1715,7 @@
 
     @Nullable
     @Override
-    public PackageParser.SigningDetails getSigningDetails() {
+    public SigningDetails getSigningDetails() {
         return signingDetails;
     }
 
@@ -2276,7 +2277,7 @@
     }
 
     @Override
-    public ParsingPackageImpl setSigningDetails(@Nullable PackageParser.SigningDetails value) {
+    public ParsingPackageImpl setSigningDetails(@Nullable SigningDetails value) {
         signingDetails = value;
         return this;
     }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index a6e189d..d5bd3a9 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -26,8 +26,8 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageParser;
 import android.content.pm.ServiceInfo;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -768,7 +768,7 @@
      * The signature data of all APKs in this package, which must be exactly the same across the
      * base and splits.
      */
-    PackageParser.SigningDetails getSigningDetails();
+    SigningDetails getSigningDetails();
 
     /**
      * @see ApplicationInfo#splitClassLoaderNames
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index dce242c..e96a733 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -47,8 +47,8 @@
 import android.content.pm.PackageManager.Property;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.component.ComponentParseUtils;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedActivityUtils;
@@ -74,6 +74,7 @@
 import android.content.pm.parsing.result.ParseInput.DeferredError;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.permission.CompatibilityPermissionInfo;
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
 import android.content.pm.split.SplitAssetLoader;
@@ -905,7 +906,7 @@
             );
         }
 
-        convertNewPermissions(pkg);
+        convertCompatPermissions(pkg);
 
         convertSplitPermissions(pkg);
 
@@ -2791,31 +2792,16 @@
         }
     }
 
-    private static void convertNewPermissions(ParsingPackage pkg) {
-        final int NP = PackageParser.NEW_PERMISSIONS.length;
-        StringBuilder newPermsMsg = null;
-        for (int ip = 0; ip < NP; ip++) {
-            final PackageParser.NewPermissionInfo npi
-                    = PackageParser.NEW_PERMISSIONS[ip];
-            if (pkg.getTargetSdkVersion() >= npi.sdkVersion) {
+    private static void convertCompatPermissions(ParsingPackage pkg) {
+        for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) {
+            final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i];
+            if (pkg.getTargetSdkVersion() >= info.sdkVersion) {
                 break;
             }
-            if (!pkg.getRequestedPermissions().contains(npi.name)) {
-                if (newPermsMsg == null) {
-                    newPermsMsg = new StringBuilder(128);
-                    newPermsMsg.append(pkg.getPackageName());
-                    newPermsMsg.append(": compat added ");
-                } else {
-                    newPermsMsg.append(' ');
-                }
-                newPermsMsg.append(npi.name);
-                pkg.addUsesPermission(new ParsedUsesPermission(npi.name, 0))
-                        .addImplicitPermission(npi.name);
+            if (!pkg.getRequestedPermissions().contains(info.name)) {
+                pkg.addImplicitPermission(info.name);
             }
         }
-        if (newPermsMsg != null) {
-            Slog.i(TAG, newPermsMsg.toString());
-        }
     }
 
     private void convertSplitPermissions(ParsingPackage pkg) {
@@ -2831,8 +2817,7 @@
             for (int in = 0; in < newPerms.size(); in++) {
                 final String perm = newPerms.get(in);
                 if (!requestedPermissions.contains(perm)) {
-                    pkg.addUsesPermission(new ParsedUsesPermission(perm, 0))
-                            .addImplicitPermission(perm);
+                    pkg.addImplicitPermission(perm);
                 }
             }
         }
@@ -3057,7 +3042,8 @@
         if (existingSigningDetails == SigningDetails.UNKNOWN) {
             return input.success(verified);
         } else {
-            if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
+            if (!Signature.areExactMatch(existingSigningDetails.getSignatures(),
+                    verified.getSignatures())) {
                 return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                         baseCodePath + " has mismatched certificates");
             }
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index 7ac78b7..324612d 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -119,7 +119,6 @@
             // how many APKs they're going through.
             mDeferredErrors.erase();
         }
-        mPackageName = null;
         mTargetSdkVersion = null;
         return this;
     }
diff --git a/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java b/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
new file mode 100644
index 0000000..9198b95
--- /dev/null
+++ b/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.permission;
+
+import android.Manifest;
+import android.content.pm.parsing.component.ParsedUsesPermission;
+
+/**
+ * Implements compatibility support for permissions, and old applications
+ * will be automatically granted it.
+ *
+ * Compatibility permissions are permissions that are automatically granted to
+ * packages that target an SDK prior to when the permission was introduced.
+ * Sometimes the platform makes breaking behaviour changes and hides the legacy
+ * behaviour behind a permission. In these instances, we ensure applications
+ * targeting older platform versions are implicitly granted the correct set of
+ * permissions.
+ *
+ * @hide
+ */
+public class CompatibilityPermissionInfo extends ParsedUsesPermission {
+
+    public final int sdkVersion;
+
+    /**
+     * List of new permissions that have been added since 1.0.
+     *
+     * @hide
+     */
+    public static final CompatibilityPermissionInfo[] COMPAT_PERMS =
+            new CompatibilityPermissionInfo[]{
+                    new CompatibilityPermissionInfo(Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                            android.os.Build.VERSION_CODES.DONUT, 0 /*usesPermissionFlags*/),
+                    new CompatibilityPermissionInfo(Manifest.permission.READ_PHONE_STATE,
+                            android.os.Build.VERSION_CODES.DONUT, 0 /*usesPermissionFlags*/)
+            };
+
+    private CompatibilityPermissionInfo(String name, int sdkVersion,
+            @UsesPermissionFlags int usesPermissionFlags) {
+        super(name, usesPermissionFlags);
+        this.sdkVersion = sdkVersion;
+    }
+}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 572a8a8..ad4e64b 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -506,6 +506,7 @@
         if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION
                 || type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE
                 || type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE
+                || type == Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT
                 || type == Sensor.TYPE_WRIST_TILT_GESTURE
                 || type == Sensor.TYPE_DYNAMIC_SENSOR_META || type == Sensor.TYPE_HINGE_ANGLE) {
             wakeUpSensor = true;
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index ecfc0d5..a3be415 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -346,7 +346,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface HdmiCecControl {}
 
-    // -- Supported HDM-CEC versions.
+    // -- Supported HDMI-CEC versions.
     /**
      * Version constant for HDMI-CEC v1.4b.
      *
@@ -371,23 +371,67 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface HdmiCecVersion {}
 
+    // -- Whether the Routing Control feature is enabled or disabled.
+    /**
+     * Routing Control feature enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ROUTING_CONTROL_ENABLED = 1;
+    /**
+     * Routing Control feature disabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ROUTING_CONTROL_DISABLED = 0;
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "ROUTING_CONTROL_" }, value = {
+            ROUTING_CONTROL_ENABLED,
+            ROUTING_CONTROL_DISABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RoutingControl {}
+
     // -- Scope of CEC power control messages sent by a playback device.
     /**
-     * Send CEC power control messages to TV only.
+     * Send CEC power control messages to TV only:
+     * Upon going to sleep, send {@code <Standby>} to TV only.
+     * Upon waking up, attempt to turn on the TV via {@code <One Touch Play>} but do not turn on the
+     * Audio system via {@code <System Audio Mode Request>}.
      *
      * @hide
      */
     @SystemApi
     public static final String POWER_CONTROL_MODE_TV = "to_tv";
     /**
-     * Broadcast CEC power control messages to all devices in the network.
+     * Send CEC power control messages to TV and Audio System:
+     * Upon going to sleep, send {@code <Standby>} to TV and Audio system.
+     * Upon waking up, attempt to turn on the TV via {@code <One Touch Play>} and attempt to turn on
+     * the Audio system via {@code <System Audio Mode Request>}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM = "to_tv_and_audio_system";
+    /**
+     * Broadcast CEC power control messages to all devices in the network:
+     * Upon going to sleep, send {@code <Standby>} to all devices in the network.
+     * Upon waking up, attempt to turn on the TV via {@code <One Touch Play>} and attempt to turn on
+     * the Audio system via {@code <System Audio Mode Request>}.
      *
      * @hide
      */
     @SystemApi
     public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast";
     /**
-     * Don't send any CEC power control messages.
+     * Don't send any CEC power control messages:
+     * Upon going to sleep, do not send any {@code <Standby>} message.
+     * Upon waking up, do not turn on the TV via {@code <One Touch Play>} and do not turn on the
+     * Audio system via {@code <System Audio Mode Request>}.
      *
      * @hide
      */
@@ -398,6 +442,7 @@
      */
     @StringDef(prefix = { "POWER_CONTROL_MODE_" }, value = {
             POWER_CONTROL_MODE_TV,
+            POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM,
             POWER_CONTROL_MODE_BROADCAST,
             POWER_CONTROL_MODE_NONE
     })
@@ -429,6 +474,31 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActiveSourceLostBehavior {}
 
+    // -- Whether System Audio Control is enabled or disabled.
+    /**
+     * System Audio Control enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SYSTEM_AUDIO_CONTROL_ENABLED = 1;
+    /**
+     * System Audio Control disabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SYSTEM_AUDIO_CONTROL_DISABLED = 0;
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "SYSTEM_AUDIO_CONTROL_" }, value = {
+            SYSTEM_AUDIO_CONTROL_ENABLED,
+            SYSTEM_AUDIO_CONTROL_DISABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SystemAudioControl {}
+
     // -- Whether System Audio Mode muting is enabled or disabled.
     /**
      * System Audio Mode muting enabled.
@@ -710,6 +780,13 @@
     @SystemApi
     public static final String CEC_SETTING_NAME_HDMI_CEC_VERSION = "hdmi_cec_version";
     /**
+     * Name of a setting deciding whether the Routing Control feature is enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String CEC_SETTING_NAME_ROUTING_CONTROL = "routing_control";
+    /**
      * Name of a setting deciding on the power control mode.
      *
      * @hide
@@ -725,6 +802,14 @@
     public static final String CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST =
             "power_state_change_on_active_source_lost";
     /**
+     * Name of a setting deciding whether System Audio Control is enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL =
+            "system_audio_control";
+    /**
      * Name of a setting deciding whether System Audio Muting is allowed.
      *
      * @hide
@@ -778,7 +863,7 @@
     public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY =
             "tv_wake_on_one_touch_play";
     /**
-     * Name of a setting deciding whether the device will also turn off other CEC devices
+     * Name of a setting deciding whether the TV will also turn off other CEC devices
      * when it goes to standby mode.
      *
      * @hide
@@ -842,6 +927,7 @@
         CEC_SETTING_NAME_HDMI_CEC_VERSION,
         CEC_SETTING_NAME_POWER_CONTROL_MODE,
         CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+        CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
         CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
         CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
         CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
@@ -2021,6 +2107,56 @@
     }
 
     /**
+     * Set the status of Routing Control feature.
+     *
+     * <p>This allows to enable/disable Routing Control on the device.
+     * If enabled, the switch device will route to the correct input source on
+     * receiving Routing Control related messages. If disabled, you can only
+     * switch the input via controls on this device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public void setRoutingControl(@NonNull @RoutingControl int value) {
+        if (mService == null) {
+            Log.e(TAG, "HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            mService.setCecSettingIntValue(CEC_SETTING_NAME_ROUTING_CONTROL, value);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the current status of Routing Control feature.
+     *
+     * <p>Reflects whether Routing Control is currently enabled on the device.
+     * If enabled, the switch device will route to the correct input source on
+     * receiving Routing Control related messages. If disabled, you can only
+     * switch the input via controls on this device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @RoutingControl
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public int getRoutingControl() {
+        if (mService == null) {
+            Log.e(TAG, "HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            return mService.getCecSettingIntValue(CEC_SETTING_NAME_ROUTING_CONTROL);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Set the status of Power Control.
      *
      * <p>Specifies to which devices Power Control messages should be sent:
@@ -2114,6 +2250,58 @@
     }
 
     /**
+     * Set the current status of System Audio Control.
+     *
+     * <p>Sets whether HDMI System Audio Control feature is enabled. If enabled,
+     * TV or Audio System will try to turn on the System Audio Mode if there's a
+     * connected CEC-enabled AV Receiver. Then an audio stream will be played on
+     * the AVR instead of TV speaker or Audio System speakers. If disabled, the
+     * System Audio Mode will never be activated.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public void setSystemAudioControl(@NonNull @SystemAudioControl int value) {
+        if (mService == null) {
+            Log.e(TAG, "HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL, value);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the current status of System Audio Control.
+     *
+     * <p>Reflects whether HDMI System Audio Control feature is enabled. If enabled,
+     * TV or Audio System will try to turn on the System Audio Mode if there's a
+     * connected CEC-enabled AV Receiver. Then an audio stream will be played on
+     * the AVR instead of TV speaker or Audio System speakers. If disabled, the
+     * System Audio Mode will never be activated.
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @SystemAudioControl
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public int getSystemAudioControl() {
+        if (mService == null) {
+            Log.e(TAG, "HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Set the current status of System Audio Mode muting.
      *
      * <p>Sets whether the device should be muted when System Audio Mode is turned off.
diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS
index 60d43fd..861e440 100644
--- a/core/java/android/hardware/hdmi/OWNERS
+++ b/core/java/android/hardware/hdmi/OWNERS
@@ -3,5 +3,4 @@
 include /services/core/java/com/android/server/display/OWNERS
 
 marvinramin@google.com
-nchalko@google.com
 lcnathalie@google.com
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 17116e2..e5d8620 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -435,7 +435,7 @@
     /**
      * Enables an InputDevice.
      * <p>
-     * Requires {@link android.Manifest.permissions.DISABLE_INPUT_DEVICE}.
+     * Requires {@link android.Manifest.permission.DISABLE_INPUT_DEVICE}.
      * </p>
      *
      * @param id The input device Id.
@@ -454,7 +454,7 @@
     /**
      * Disables an InputDevice.
      * <p>
-     * Requires {@link android.Manifest.permissions.DISABLE_INPUT_DEVICE}.
+     * Requires {@link android.Manifest.permission.DISABLE_INPUT_DEVICE}.
      * </p>
      *
      * @param id The input device Id.
@@ -831,7 +831,7 @@
      * Sets the TouchCalibration to apply to the specified input device's coordinates.
      * <p>
      * This method may have the side-effect of causing the input device in question
-     * to be reconfigured. Requires {@link android.Manifest.permissions.SET_INPUT_CALIBRATION}.
+     * to be reconfigured. Requires {@link android.Manifest.permission.SET_INPUT_CALIBRATION}.
      * </p>
      *
      * @param inputDeviceDescriptor The input device descriptor.
@@ -874,7 +874,7 @@
     /**
      * Sets the mouse pointer speed.
      * <p>
-     * Requires {@link android.Manifest.permissions.WRITE_SETTINGS}.
+     * Requires {@link android.Manifest.permission.WRITE_SETTINGS}.
      * </p>
      *
      * @param context The application context.
@@ -1285,7 +1285,7 @@
      * @param inputPort The port of the input device.
      * @param displayPort The physical port of the associated display.
      * <p>
-     * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1302,7 +1302,7 @@
      * static association for the cleared input port will be restored.
      * @param inputPort The port of the input device to be cleared.
      * <p>
-     * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1320,7 +1320,7 @@
      * @param inputDeviceName The name of the input device.
      * @param displayUniqueId The unique id of the associated display.
      * <p>
-     * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
@@ -1337,7 +1337,7 @@
      * Removes a runtime association between the input device and display.
      * @param inputDeviceName The name of the input device.
      * <p>
-     * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+     * Requires {@link android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
      * </p>
      * @hide
      */
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index a5c9a7f..ad0dc09 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -19,19 +19,19 @@
 import android.annotation.Nullable;
 import android.media.AudioFormat;
 import android.media.audio.common.AudioConfig;
-import android.media.soundtrigger_middleware.AudioCapabilities;
-import android.media.soundtrigger_middleware.ConfidenceLevel;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.Phrase;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.RecognitionMode;
-import android.media.soundtrigger_middleware.SoundModel;
+import android.media.soundtrigger.AudioCapabilities;
+import android.media.soundtrigger.ConfidenceLevel;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.Phrase;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionMode;
+import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
 import android.os.ParcelFileDescriptor;
 import android.os.SharedMemory;
 
@@ -43,7 +43,7 @@
 class ConversionUtil {
     public static SoundTrigger.ModuleProperties aidl2apiModuleDescriptor(
             SoundTriggerModuleDescriptor aidlDesc) {
-        SoundTriggerModuleProperties properties = aidlDesc.properties;
+        Properties properties = aidlDesc.properties;
         return new SoundTrigger.ModuleProperties(
                 aidlDesc.handle,
                 properties.implementor,
@@ -194,19 +194,19 @@
     }
 
     public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
-            int modelHandle, RecognitionEvent aidlEvent) {
+            int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
         AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig);
         return new SoundTrigger.GenericRecognitionEvent(
                 aidlEvent.status,
-                modelHandle, aidlEvent.captureAvailable, aidlEvent.captureSession,
+                modelHandle, aidlEvent.captureAvailable, captureSession,
                 aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
                 audioFormat, aidlEvent.data);
     }
 
     public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
-            int modelHandle,
+            int modelHandle, int captureSession,
             PhraseRecognitionEvent aidlEvent) {
         SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
                 new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
@@ -218,7 +218,7 @@
         AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig);
         return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
                 aidlEvent.common.captureAvailable,
-                aidlEvent.common.captureSession, aidlEvent.common.captureDelayMs,
+                captureSession, aidlEvent.common.captureDelayMs,
                 aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
                 audioFormat, aidlEvent.common.data,
                 apiExtras);
@@ -328,9 +328,9 @@
     public static int api2aidlModelParameter(int apiParam) {
         switch (apiParam) {
             case ModelParams.THRESHOLD_FACTOR:
-                return android.media.soundtrigger_middleware.ModelParameter.THRESHOLD_FACTOR;
+                return android.media.soundtrigger.ModelParameter.THRESHOLD_FACTOR;
             default:
-                return android.media.soundtrigger_middleware.ModelParameter.INVALID;
+                return android.media.soundtrigger.ModelParameter.INVALID;
         }
     }
 
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 11f3e45..163e6f0 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
 import static android.Manifest.permission.RECORD_AUDIO;
 import static android.Manifest.permission.SOUNDTRIGGER_DELEGATE_IDENTITY;
+import static android.system.OsConstants.EBUSY;
 import static android.system.OsConstants.EINVAL;
 import static android.system.OsConstants.ENODEV;
 import static android.system.OsConstants.ENOSYS;
@@ -41,9 +42,9 @@
 import android.media.permission.ClearCallingIdentityContext;
 import android.media.permission.Identity;
 import android.media.permission.SafeCloseable;
+import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.media.soundtrigger_middleware.Status;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -91,6 +92,8 @@
     public static final int STATUS_DEAD_OBJECT = -EPIPE;
     /** @hide */
     public static final int STATUS_INVALID_OPERATION = -ENOSYS;
+    /** @hide */
+    public static final int STATUS_BUSY = -EBUSY;
 
     /*****************************************************************************
      * A ModuleProperties describes a given sound trigger hardware module
@@ -1835,120 +1838,6 @@
         }
     }
 
-    /**
-     *  Status codes for {@link SoundModelEvent}
-     */
-    /**
-     * Sound Model was updated
-     *
-     * @hide
-     */
-    public static final int SOUNDMODEL_STATUS_UPDATED = 0;
-
-    /**
-     *  A SoundModelEvent is provided by the
-     *  {@link StatusListener#onSoundModelUpdate(SoundModelEvent)}
-     *  callback when a sound model has been updated by the implementation
-     *
-     *  @hide
-     */
-    public static class SoundModelEvent implements Parcelable {
-        /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */
-        public final int status;
-        /** The updated sound model handle */
-        public final int soundModelHandle;
-        /** New sound model data */
-        @NonNull
-        public final byte[] data;
-
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        SoundModelEvent(int status, int soundModelHandle, @Nullable byte[] data) {
-            this.status = status;
-            this.soundModelHandle = soundModelHandle;
-            this.data = data != null ? data : new byte[0];
-        }
-
-        public static final @android.annotation.NonNull Parcelable.Creator<SoundModelEvent> CREATOR
-                = new Parcelable.Creator<SoundModelEvent>() {
-            public SoundModelEvent createFromParcel(Parcel in) {
-                return SoundModelEvent.fromParcel(in);
-            }
-
-            public SoundModelEvent[] newArray(int size) {
-                return new SoundModelEvent[size];
-            }
-        };
-
-        private static SoundModelEvent fromParcel(Parcel in) {
-            int status = in.readInt();
-            int soundModelHandle = in.readInt();
-            byte[] data = in.readBlob();
-            return new SoundModelEvent(status, soundModelHandle, data);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(status);
-            dest.writeInt(soundModelHandle);
-            dest.writeBlob(data);
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + Arrays.hashCode(data);
-            result = prime * result + soundModelHandle;
-            result = prime * result + status;
-            return result;
-        }
-
-        @Override
-        public boolean equals(@Nullable Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            SoundModelEvent other = (SoundModelEvent) obj;
-            if (!Arrays.equals(data, other.data))
-                return false;
-            if (soundModelHandle != other.soundModelHandle)
-                return false;
-            if (status != other.status)
-                return false;
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
-                    + ", data=" + (data == null ? 0 : data.length) + "]";
-        }
-    }
-
-    /**
-     *  Native service state. {@link StatusListener#onServiceStateChange(int)}
-     */
-    // Keep in sync with system/core/include/system/sound_trigger.h
-    /**
-     * Sound trigger service is enabled
-     *
-     * @hide
-     */
-    public static final int SERVICE_STATE_ENABLED = 0;
-    /**
-     * Sound trigger service is disabled
-     *
-     * @hide
-     */
-    public static final int SERVICE_STATE_DISABLED = 1;
     private static Object mServiceLock = new Object();
     private static ISoundTriggerMiddlewareService mService;
 
@@ -1975,6 +1864,8 @@
                     return STATUS_DEAD_OBJECT;
                 case Status.INTERNAL_ERROR:
                     return STATUS_ERROR;
+                case Status.RESOURCE_CONTENTION:
+                    return STATUS_BUSY;
             }
             return STATUS_ERROR;
         }
@@ -2224,27 +2115,28 @@
      *
      * @hide
      */
-    public static interface StatusListener {
+    public interface StatusListener {
         /**
          * Called when recognition succeeds of fails
          */
-        public abstract void onRecognition(RecognitionEvent event);
+        void onRecognition(RecognitionEvent event);
 
         /**
-         * Called when a sound model has been updated
+         * Called when a sound model has been preemptively unloaded by the underlying
+         * implementation.
          */
-        public abstract void onSoundModelUpdate(SoundModelEvent event);
+        void onModelUnloaded(int modelHandle);
 
         /**
-         * Called when the sound trigger native service state changes.
-         * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED},
-         * {@link SoundTrigger#SERVICE_STATE_DISABLED}
+         * Called whenever underlying conditions change, such that load/start operations that have
+         * previously failed or got preempted may now succeed. This is not a guarantee, merely a
+         * hint that the client may want to retry operations.
          */
-        public abstract void onServiceStateChange(int state);
+        void onResourcesAvailable();
 
         /**
          * Called when the sound trigger native service dies
          */
-        public abstract void onServiceDied();
+        void onServiceDied();
     }
 }
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 431c99d..bf4b514 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -22,13 +22,13 @@
 import android.media.permission.ClearCallingIdentityContext;
 import android.media.permission.Identity;
 import android.media.permission.SafeCloseable;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.SoundModel;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -48,7 +48,8 @@
 
     private static final int EVENT_RECOGNITION = 1;
     private static final int EVENT_SERVICE_DIED = 2;
-    private static final int EVENT_SERVICE_STATE_CHANGE = 3;
+    private static final int EVENT_RESOURCES_AVAILABLE = 3;
+    private static final int EVENT_MODEL_UNLOADED = 4;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private int mId;
     private EventHandlerDelegate mEventHandlerDelegate;
@@ -120,6 +121,7 @@
      * @param soundModelHandle an array of int where the sound model handle will be returned.
      * @return - {@link SoundTrigger#STATUS_OK} in case of success
      *         - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error
+     *         - {@link SoundTrigger#STATUS_BUSY} in case of transient resource constraints
      *         - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have
      *         system permission
      *         - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
@@ -181,6 +183,7 @@
      *  recognition mode, keyphrases, users, minimum confidence levels...
      * @return - {@link SoundTrigger#STATUS_OK} in case of success
      *         - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error
+     *         - {@link SoundTrigger#STATUS_BUSY} in case of transient resource constraints
      *         - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have
      *         system permission
      *         - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
@@ -333,8 +336,11 @@
                             listener.onRecognition(
                                     (SoundTrigger.RecognitionEvent) msg.obj);
                             break;
-                        case EVENT_SERVICE_STATE_CHANGE:
-                            listener.onServiceStateChange((int) msg.obj);
+                        case EVENT_RESOURCES_AVAILABLE:
+                            listener.onResourcesAvailable();
+                            break;
+                        case EVENT_MODEL_UNLOADED:
+                            listener.onModelUnloaded((Integer) msg.obj);
                             break;
                         case EVENT_SERVICE_DIED:
                             listener.onServiceDied();
@@ -348,27 +354,32 @@
         }
 
         @Override
-        public synchronized void onRecognition(int handle, RecognitionEvent event)
+        public synchronized void onRecognition(int handle, RecognitionEvent event,
+                int captureSession)
                 throws RemoteException {
             Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
-                    ConversionUtil.aidl2apiRecognitionEvent(handle, event));
+                    ConversionUtil.aidl2apiRecognitionEvent(handle, captureSession, event));
             mHandler.sendMessage(m);
         }
 
         @Override
-        public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEvent event)
+        public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEvent event,
+                int captureSession)
                 throws RemoteException {
             Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
-                    ConversionUtil.aidl2apiPhraseRecognitionEvent(handle, event));
+                    ConversionUtil.aidl2apiPhraseRecognitionEvent(handle, captureSession, event));
             mHandler.sendMessage(m);
         }
 
         @Override
-        public synchronized void onRecognitionAvailabilityChange(boolean available)
-                throws RemoteException {
-            Message m = mHandler.obtainMessage(EVENT_SERVICE_STATE_CHANGE,
-                    available ? SoundTrigger.SERVICE_STATE_ENABLED
-                            : SoundTrigger.SERVICE_STATE_DISABLED);
+        public void onModelUnloaded(int modelHandle) throws RemoteException {
+            Message m = mHandler.obtainMessage(EVENT_MODEL_UNLOADED, modelHandle);
+            mHandler.sendMessage(m);
+        }
+
+        @Override
+        public synchronized void onResourcesAvailable() throws RemoteException {
+            Message m = mHandler.obtainMessage(EVENT_RESOURCES_AVAILABLE);
             mHandler.sendMessage(m);
         }
 
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 964d7c1..c29a948 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -384,8 +384,9 @@
             "android.hardware.usb.extra.ACCESSORY_START";
 
     /**
-     * A long extra indicating ms from boot to sent {@link #ACTION_USB_ACCESSORY_HANDSHAKE}
-     * This is obtained with SystemClock.elapsedRealtime()
+
+     * A long extra indicating the timestamp just before
+     * sending {@link #ACTION_USB_ACCESSORY_HANDSHAKE}.
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
      * {@hide}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 3cd13a2..17d4ae6 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -18,16 +18,23 @@
 
 import android.annotation.MainThread;
 import android.annotation.NonNull;
-import android.app.Service;
+import android.annotation.Nullable;
+import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.util.proto.ProtoOutputStream;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodSession;
+import android.window.WindowProviderService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -44,9 +51,22 @@
  * implement.  This base class takes care of reporting your InputMethod from
  * the service when clients bind to it, but provides no standard implementation
  * of the InputMethod interface itself.  Derived classes must implement that
- * interface.
+ * interface.</p>
+ *
+ * <p>After {@link android.os.Build.VERSION_CODES#S}, the maximum possible area to show the soft
+ * input may not be the entire screen. For example, some devices may support to show the soft input
+ * on only half of screen.</p>
+ *
+ * <p>In that case, moving the soft input from one half screen to another will trigger a
+ * {@link android.content.res.Resources} update to match the new {@link Configuration} and
+ * this {@link AbstractInputMethodService} may also receive a
+ * {@link #onConfigurationChanged(Configuration)} callback if there's notable configuration changes
+ * </p>
+ *
+ * @see android.content.ComponentCallbacks#onConfigurationChanged(Configuration)
+ * @see Context#isUiContext Context#isUiContext to see the concept of UI Context.
  */
-public abstract class AbstractInputMethodService extends Service
+public abstract class AbstractInputMethodService extends WindowProviderService
         implements KeyEvent.Callback {
     private InputMethod mInputMethod;
     
@@ -272,9 +292,33 @@
     public void notifyUserActionIfNecessary() {
     }
 
+    // TODO(b/149463653): remove it in T. We missed the API deadline in S.
     /** @hide */
     @Override
     public final boolean isUiContext() {
         return true;
     }
+
+    /** @hide */
+    @Override
+    public final int getWindowType() {
+        return WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+    }
+
+    /** @hide */
+    @Override
+    @Nullable
+    public final Bundle getWindowContextOptions() {
+        return null;
+    }
+
+    /** @hide */
+    @Override
+    public final int getInitialDisplayId() {
+        try {
+            return WindowManagerGlobal.getWindowManagerService().getImeDisplayId();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 881e0cf..18c6256 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -629,10 +629,13 @@
                 throw new IllegalStateException(
                         "attachToken() must be called at most once. token=" + token);
             }
+            attachToWindowToken(token);
             mToken = token;
             mWindow.setToken(token);
         }
 
+        // TODO(b/149463653): remove updateInputMethodDisplay(int displayId) since we'll get the
+        // right display by attachToWindowToken
         /**
          * {@inheritDoc}
          * @hide
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 3bde6fa..1d07a03 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -26,8 +26,10 @@
 import android.telephony.Annotation.NetworkType;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.net.module.util.NetworkCapabilitiesUtils;
 import com.android.net.module.util.NetworkIdentityUtils;
 
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
@@ -121,11 +123,37 @@
         }
         builder.append(", metered=").append(mMetered);
         builder.append(", defaultNetwork=").append(mDefaultNetwork);
-        // TODO(180557699): Print a human readable string for OEM managed state.
-        builder.append(", oemManaged=").append(mOemManaged);
+        builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
         return builder.append("}").toString();
     }
 
+    /**
+     * Get the human readable representation of a bitfield representing the OEM managed state of a
+     * network.
+     */
+    static String getOemManagedNames(int oemManaged) {
+        if (oemManaged == OEM_NONE) {
+            return "OEM_NONE";
+        }
+        final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged);
+        final ArrayList<String> oemManagedNames = new ArrayList<String>();
+        for (int position : bitPositions) {
+            oemManagedNames.add(nameOfOemManaged(1 << position));
+        }
+        return String.join(",", oemManagedNames);
+    }
+
+    private static String nameOfOemManaged(int oemManagedBit) {
+        switch (oemManagedBit) {
+            case OEM_PAID:
+                return "OEM_PAID";
+            case OEM_PRIVATE:
+                return "OEM_PRIVATE";
+            default:
+                return "Invalid(" + oemManagedBit + ")";
+        }
+    }
+
     public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 249154a..68917a8 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -427,7 +427,7 @@
             builder.append(", subType=").append(mSubType);
         }
         if (mOemManaged != OEM_MANAGED_ALL) {
-            builder.append(", oemManaged=").append(mOemManaged);
+            builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
         }
         builder.append(", subscriberIdMatchRule=")
                 .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule));
@@ -781,6 +781,19 @@
         }
     }
 
+    private static String getOemManagedNames(int oemManaged) {
+        switch (oemManaged) {
+            case OEM_MANAGED_ALL:
+                return "OEM_MANAGED_ALL";
+            case OEM_MANAGED_NO:
+                return "OEM_MANAGED_NO";
+            case OEM_MANAGED_YES:
+                return "OEM_MANAGED_YES";
+            default:
+                return NetworkIdentity.getOemManagedNames(oemManaged);
+        }
+    }
+
     /**
      * Examine the given template and normalize if it refers to a "merged"
      * mobile subscriber. We pick the "lowest" merged subscriber as the primary
diff --git a/core/java/android/net/vcn/OWNERS b/core/java/android/net/vcn/OWNERS
index 33b9f0f..2441e77 100644
--- a/core/java/android/net/vcn/OWNERS
+++ b/core/java/android/net/vcn/OWNERS
@@ -3,5 +3,5 @@
 benedictwong@google.com
 ckesting@google.com
 evitayan@google.com
+junyin@google.com
 nharold@google.com
-jchalard@google.com
\ No newline at end of file
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 2c088e2..4d55906 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -322,7 +322,9 @@
      *
      * @return Instance of {@link CellularBatteryStats}.
      */
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.BATTERY_STATS,
+            android.Manifest.permission.UPDATE_DEVICE_STATS})
     public @NonNull CellularBatteryStats getCellularBatteryStats() {
         try {
             return mBatteryStats.getCellularBatteryStats();
@@ -337,7 +339,9 @@
      *
      * @return Instance of {@link WifiBatteryStats}.
      */
-    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.BATTERY_STATS,
+            android.Manifest.permission.UPDATE_DEVICE_STATS})
     public @NonNull WifiBatteryStats getWifiBatteryStats() {
         try {
             return mBatteryStats.getWifiBatteryStats();
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index f483752..b128f68 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -82,8 +82,6 @@
 
     public static final int AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT = 2;
 
-    private static final int STATSD_PULL_ATOM_MAX_BYTES = 45000;
-
     // XML tags and attributes for BatteryUsageStats persistence
     static final String XML_TAG_BATTERY_USAGE_STATS = "battery_usage_stats";
     static final String XML_TAG_AGGREGATE = "aggregate";
@@ -112,6 +110,8 @@
     static final String XML_ATTR_TIME_IN_FOREGROUND = "time_in_foreground";
     static final String XML_ATTR_TIME_IN_BACKGROUND = "time_in_background";
 
+    private static final int STATSD_PULL_ATOM_MAX_BYTES = 45000;
+
     private final int mDischargePercentage;
     private final double mBatteryCapacityMah;
     private final long mStatsStartTimestampMs;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index a5b7e99..d7851a5 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1351,7 +1351,11 @@
     public static final boolean IS_USER = "user".equals(TYPE);
 
     /**
-     * Whether this build is running inside a container.
+     * Whether this build is running on ARC, the Android Runtime for Chrome
+     * (https://chromium.googlesource.com/chromiumos/docs/+/master/containers_and_vms.md).
+     * Prior to R this was implemented as a container but from R this will be
+     * a VM. The name of the property remains ro.boot.conntainer as it is
+     * referenced in other projects.
      *
      * We should try to avoid checking this flag if possible to minimize
      * unnecessarily diverging from non-container Android behavior.
@@ -1362,7 +1366,7 @@
      * For higher-level behavior differences, other checks should be preferred.
      * @hide
      */
-    public static final boolean IS_CONTAINER =
+    public static final boolean IS_ARC =
             SystemProperties.getBoolean("ro.boot.container", false);
 
     /**
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 2ed0bad..308e6d5 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -189,13 +189,11 @@
         }
 
         @UnsupportedAppUsage
-        @Deprecated
         public File getExternalStorageDirectory() {
             return getExternalDirs()[0];
         }
 
         @UnsupportedAppUsage
-        @Deprecated
         public File getExternalStoragePublicDirectory(String type) {
             return buildExternalStoragePublicDirs(type)[0];
         }
@@ -698,11 +696,7 @@
      *
      * @see #getExternalStorageState()
      * @see #isExternalStorageRemovable()
-     * @deprecated Alternatives such as {@link Context#getExternalFilesDir(String)},
-     *             {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT} offer better
-     *             performance.
      */
-    @Deprecated
     public static File getExternalStorageDirectory() {
         throwIfUserRequired();
         return sCurrentUser.getExternalDirs()[0];
@@ -1009,11 +1003,7 @@
      * @return Returns the File path for the directory. Note that this directory
      *         may not yet exist, so you must make sure it exists before using
      *         it such as with {@link File#mkdirs File.mkdirs()}.
-     * @deprecated Alternatives such as {@link Context#getExternalFilesDir(String)},
-     *             {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT} offer better
-     *             performance.
      */
-    @Deprecated
     public static File getExternalStoragePublicDirectory(String type) {
         throwIfUserRequired();
         return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index be21fea..1651bfc 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -26,8 +26,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
@@ -37,9 +35,6 @@
 
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
@@ -88,9 +83,6 @@
     private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*";
     private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
 
-    // ANGLE related properties.
-    private static final String ANGLE_RULES_FILE = "a4a_rules.json";
-    private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
     private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
     private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
             "android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
@@ -164,21 +156,14 @@
         Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
                 + "set to: '" + devOptIn + "'");
 
-        // We only want to use ANGLE if the app is in the allowlist, or the developer has
-        // explicitly chosen something other than default driver.
-        // The allowlist will be generated by the ANGLE APK at both boot time and
-        // ANGLE update time. It will only include apps mentioned in the rules file.
-        final boolean allowed = checkAngleAllowlist(context, coreSettings, packageName);
+        // We only want to use ANGLE if the developer has explicitly chosen something other than
+        // default driver.
         final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
-
-        if (allowed) {
-            Log.v(TAG, "ANGLE allowlist includes " + packageName);
-        }
         if (requested) {
             Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
         }
 
-        return allowed || requested;
+        return requested;
     }
 
     private int getVulkanVersion(PackageManager pm) {
@@ -475,117 +460,6 @@
     }
 
     /**
-     * Attempt to setup ANGLE with a temporary rules file.
-     * True: Temporary rules file was loaded.
-     * False: Temporary rules file was *not* loaded.
-     */
-    private boolean setupAngleWithTempRulesFile(Context context,
-                                                String packageName,
-                                                String paths,
-                                                String devOptIn) {
-        /**
-         * We only want to load a temp rules file for:
-         *  - apps that are marked 'debuggable' in their manifest
-         *  - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
-         *    debugging (PR_SET_DUMPABLE).
-         */
-        if (!isDebuggable()) {
-            Log.v(TAG, "Skipping loading temporary rules file");
-            return false;
-        }
-
-        final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
-
-        if (TextUtils.isEmpty(angleTempRules)) {
-            Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
-            return false;
-        }
-
-        Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
-
-        final File tempRulesFile = new File(angleTempRules);
-        if (tempRulesFile.exists()) {
-            Log.i(TAG, angleTempRules + " exists, loading file.");
-            try {
-                final FileInputStream stream = new FileInputStream(angleTempRules);
-
-                try {
-                    final FileDescriptor rulesFd = stream.getFD();
-                    final long rulesOffset = 0;
-                    final long rulesLength = stream.getChannel().size();
-                    Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
-
-                    setAngleInfo(paths, packageName, devOptIn, null,
-                            rulesFd, rulesOffset, rulesLength);
-
-                    stream.close();
-
-                    // We successfully setup ANGLE, so return with good status
-                    return true;
-                } catch (IOException e) {
-                    Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
-                }
-            } catch (FileNotFoundException e) {
-                Log.w(TAG, "Temp ANGLE rules file not found: " + e);
-            } catch (SecurityException e) {
-                Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
-     * True: APK rules file was loaded.
-     * False: APK rules file was *not* loaded.
-     */
-    private boolean setupAngleRulesApk(String anglePkgName,
-            ApplicationInfo angleInfo,
-            PackageManager pm,
-            String packageName,
-            String paths,
-            String devOptIn,
-            String[] features) {
-        // Pass the rules file to loader for ANGLE decisions
-        try {
-            final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
-
-            try {
-                final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
-
-                setAngleInfo(paths, packageName, devOptIn, features, assetsFd.getFileDescriptor(),
-                        assetsFd.getStartOffset(), assetsFd.getLength());
-
-                assetsFd.close();
-
-                return true;
-            } catch (IOException e) {
-                Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
-                        + " from '" + anglePkgName + "': " + e);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
-        }
-
-        return false;
-    }
-
-    /**
-     * Pull ANGLE allowlist from GlobalSettings and compare against current package
-     */
-    private boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
-        final ContentResolver contentResolver = context.getContentResolver();
-        final List<String> angleAllowlist =
-                getGlobalSettingsString(contentResolver, bundle,
-                    Settings.Global.ANGLE_ALLOWLIST);
-
-        if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist);
-
-        return angleAllowlist.contains(packageName);
-    }
-
-    /**
      * Pass ANGLE details down to trigger enable logic
      *
      * @param context
@@ -648,27 +522,16 @@
         if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
 
         // If the user has set the developer option to something other than default,
-        // we need to call setupAngleRulesApk() with the package name and the developer
+        // we need to call setAngleInfo() with the package name and the developer
         // option value (native/angle/other). Then later when we are actually trying to
         // load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before
         // and can confidently answer yes/no based on the previously set developer
         // option value.
         final String devOptIn = getDriverForPackage(context, bundle, packageName);
+        final String[] features = getAngleEglFeatures(context, bundle);
 
-        if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
-            // We setup ANGLE with a temp rules file, so we're done here.
-            return true;
-        }
-
-        String[] features = getAngleEglFeatures(context, bundle);
-
-        if (setupAngleRulesApk(
-                anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
-            // ANGLE with rules is set up from the APK, hence return.
-            return true;
-        }
-
-        return false;
+        setAngleInfo(paths, packageName, devOptIn, features);
+        return true;
     }
 
     /**
@@ -956,7 +819,7 @@
     private static native void setGpuStats(String driverPackageName, String driverVersionName,
             long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
     private static native void setAngleInfo(String path, String appPackage, String devOptIn,
-            String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength);
+            String[] features);
     private static native boolean getShouldUseAngle(String packageName);
     private static native boolean setInjectLayersPrSetDumpable();
 
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index e5e9b5f..cad6e66 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -316,7 +316,7 @@
                         new MyReadMapCallback()));
             }
         }
-        return EMPTY;
+        return new PersistableBundle();  // An empty mutable PersistableBundle
     }
 
     @Override
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 136e3de..f9b1695 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -93,6 +94,18 @@
         }
     }
 
+    /**
+     * Creates from existing shared memory passed as {@link ParcelFileDesciptor}.
+     *
+     * @param fd File descriptor of shared memory passed as {@link #ParcelFileDescriptor}.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static @NonNull SharedMemory create(@NonNull ParcelFileDescriptor fd) {
+        return new SharedMemory(fd.getFileDescriptor());
+    }
+
     private static final int PROT_MASK = OsConstants.PROT_READ | OsConstants.PROT_WRITE
             | OsConstants.PROT_EXEC | OsConstants.PROT_NONE;
 
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 44c3d61..7455f1f 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -115,20 +115,18 @@
  *
  * <pre>
  * public void onCreate() {
- *     if (DEVELOPER_MODE) {
- *         StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
- *                 .detectDiskReads()
- *                 .detectDiskWrites()
- *                 .detectNetwork()   // or .detectAll() for all detectable problems
- *                 .penaltyLog()
- *                 .build());
- *         StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
- *                 .detectLeakedSqlLiteObjects()
- *                 .detectLeakedClosableObjects()
- *                 .penaltyLog()
- *                 .penaltyDeath()
- *                 .build());
- *     }
+ *     StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
+ *             .detectDiskReads()
+ *             .detectDiskWrites()
+ *             .detectNetwork()   // or .detectAll() for all detectable problems
+ *             .penaltyLog()
+ *             .build());
+ *     StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
+ *             .detectLeakedSqlLiteObjects()
+ *             .detectLeakedClosableObjects()
+ *             .penaltyLog()
+ *             .penaltyDeath()
+ *             .build());
  *     super.onCreate();
  * }
  * </pre>
@@ -147,9 +145,7 @@
  * <p class="note">StrictMode is not a security mechanism and is not guaranteed to find all disk or
  * network accesses. While it does propagate its state across process boundaries when doing {@link
  * android.os.Binder} calls, it's still ultimately a best effort mechanism. Notably, disk or network
- * access from JNI calls won't necessarily trigger it. Future versions of Android may catch more (or
- * fewer) operations, so you should never leave StrictMode enabled in applications distributed on
- * Google Play.
+ * access from JNI calls won't necessarily trigger it.
  */
 public final class StrictMode {
     private static final String TAG = "StrictMode";
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index d7893e4..feffcbd 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -352,6 +352,8 @@
     /**
      * Vibrate constantly for the specified period of time.
      *
+     * <p>The app should be in foreground for the vibration to happen.</p>
+     *
      * @param milliseconds The number of milliseconds to vibrate.
      * @deprecated Use {@link #vibrate(VibrationEffect)} instead.
      */
@@ -364,6 +366,9 @@
     /**
      * Vibrate constantly for the specified period of time.
      *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
      * @param milliseconds The number of milliseconds to vibrate.
      * @param attributes   {@link AudioAttributes} corresponding to the vibration. For example,
      *                     specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
@@ -398,6 +403,8 @@
      * to start the repeat, or -1 to disable repeating.
      * </p>
      *
+     * <p>The app should be in foreground for the vibration to happen.</p>
+     *
      * @param pattern an array of longs of times for which to turn the vibrator on or off.
      * @param repeat  the index into pattern at which to repeat, or -1 if
      *                you don't want to repeat.
@@ -423,6 +430,9 @@
      * to start the repeat, or -1 to disable repeating.
      * </p>
      *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
      * @param pattern    an array of longs of times for which to turn the vibrator on or off.
      * @param repeat     the index into pattern at which to repeat, or -1 if
      *                   you don't want to repeat.
@@ -450,11 +460,30 @@
         }
     }
 
+    /**
+     * Vibrate with a given effect.
+     *
+     * <p>The app should be in foreground for the vibration to happen.</p>
+     *
+     * @param vibe {@link VibrationEffect} describing the vibration to be performed.
+     */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
     public void vibrate(VibrationEffect vibe) {
         vibrate(vibe, null);
     }
 
+    /**
+     * Vibrate with a given effect.
+     *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
+     * @param vibe       {@link VibrationEffect} describing the vibration to be performed.
+     * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
+     *                   specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
+     *                   {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
+     *                   vibrations associated with incoming calls.
+     */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
     public void vibrate(VibrationEffect vibe, AudioAttributes attributes) {
         vibrate(Process.myUid(), mPackageName, vibe, null, attributes);
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 9385402c..fbac954 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -198,9 +198,9 @@
     void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
     void fixupAppDir(in String path) = 89;
     void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
-    void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91;
-    void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92;
-    PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 93;
-    boolean isAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 94;
-    int getExternalStorageMountMode(int uid, in String packageName) = 95;
-}
+    PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 91;
+    void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 92;
+    void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 93;
+    int getExternalStorageMountMode(int uid, in String packageName) = 94;
+    boolean isAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 95;
+}
\ No newline at end of file
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 400b312..69a09fb 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -214,7 +214,7 @@
 
         return AudioManager.getAudioProductStrategies().stream()
                 .map(strategy -> strategy.getVolumeGroupIdForAudioAttributes(
-                        AudioProductStrategy.sDefaultAttributes))
+                        AudioProductStrategy.getDefaultAttributes()))
                 .filter(volumeGroupId -> volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP)
                 .findFirst()
                 .orElse(AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 376d942..b3d60a5 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8594,6 +8594,12 @@
      * <p>
      * Contacts-specific settings for various {@link Account}'s.
      * </p>
+     * <p>
+     * A settings entry for an account is created automatically when a raw contact or group
+     * is inserted that references it. Settings entries cannot be deleted as long as raw
+     * contacts or groups continue to reference it; in order to delete a settings entry all
+     * raw contacts and groups referencing the account must be deleted first.
+     * </p>
      * <h2>Columns</h2>
      * <table class="jd-sumtable">
      * <tr>
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 431bf4c..de88618 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -432,6 +432,15 @@
     public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
 
     /**
+     * Namespace for swcodec native related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native";
+
+
+    /**
      * Namespace for System UI related features.
      *
      * @hide
@@ -597,6 +606,14 @@
     @TestApi
     public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
 
+    /**
+     * Namespace for App Compat Overrides related features.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
@@ -851,32 +868,31 @@
     /**
      * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device
      * config values. This is intended for use during tests to prevent a sync operation clearing
-     * config values, which could influence the outcome of the tests, i.e. by changing behavior.
+     * config values which could influence the outcome of the tests, i.e. by changing behavior.
      *
      * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
      *     {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
      *     Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
      *
-     * @see #isSyncDisabled()
+     * @see #getSyncDisabledMode()
      * @hide
      */
     @RequiresPermission(WRITE_DEVICE_CONFIG)
-    public static void setSyncDisabled(@SyncDisabledMode int syncDisabledMode) {
+    public static void setSyncDisabledMode(@SyncDisabledMode int syncDisabledMode) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
-        Settings.Config.setSyncDisabled(contentResolver, syncDisabledMode);
+        Settings.Config.setSyncDisabledMode(contentResolver, syncDisabledMode);
     }
 
     /**
-     * Returns the current state of sync disabling, {@code true} when disabled, {@code false}
-     * otherwise.
+     * Returns the current mode of sync disabling.
      *
-     * @see #setSyncDisabled(int)
+     * @see #setSyncDisabledMode(int)
      * @hide
      */
     @RequiresPermission(WRITE_DEVICE_CONFIG)
-    public static boolean isSyncDisabled() {
+    public static @SyncDisabledMode int getSyncDisabledMode() {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
-        return Settings.Config.isSyncDisabled(contentResolver);
+        return Settings.Config.getSyncDisabledMode(contentResolver);
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cb87653..30c5b44 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -299,8 +299,8 @@
     public static final String KEY_CONFIG_SET_ALL_RETURN = "config_set_all_return";
 
     /** @hide */
-    public static final String KEY_CONFIG_IS_SYNC_DISABLED_RETURN =
-            "config_is_sync_disabled_return";
+    public static final String KEY_CONFIG_GET_SYNC_DISABLED_MODE_RETURN =
+            "config_get_sync_disabled_mode_return";
 
     /**
      * An int extra specifying a subscription ID.
@@ -2439,13 +2439,15 @@
     public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
 
     /** @hide - Private call() method to disable / re-enable syncs to the 'configuration' table */
-    public static final String CALL_METHOD_SET_SYNC_DISABLED_CONFIG = "SET_SYNC_DISABLED_config";
+    public static final String CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG =
+            "SET_SYNC_DISABLED_MODE_config";
 
     /**
-     * @hide - Private call() method to return whether syncs are disabled for the 'configuration'
-     * table
+     * @hide - Private call() method to return the current mode of sync disabling for the
+     * 'configuration' table
      */
-    public static final String CALL_METHOD_IS_SYNC_DISABLED_CONFIG = "IS_SYNC_DISABLED_config";
+    public static final String CALL_METHOD_GET_SYNC_DISABLED_MODE_CONFIG =
+            "GET_SYNC_DISABLED_MODE_config";
 
     /** @hide - Private call() method to register monitor callback for 'configuration' table */
     public static final String CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG =
@@ -4698,7 +4700,7 @@
          *
          * @hide
          */
-        @Readable
+        @Readable(maxTargetSdk = Build.VERSION_CODES.R)
         public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
 
         /**
@@ -10986,6 +10988,9 @@
          * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_TV} Upon going to sleep, device
          * sends {@code <Standby>} to TV only. Upon waking up, device does not turn on the Audio
          * system via {@code <System Audio Mode Request>}.</li>
+         * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM} Upon going to
+         * sleep, sends {@code <Standby>} to TV and Audio system. Upon waking up, device attempts
+         * to turn on the Audio system via {@code <System Audio Mode Request>}.</li>
          * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_BROADCAST} Upon going to sleep,
          * device sends {@code <Standby>} to all devices in the network. Upon waking up, device
          * attempts to turn on the Audio system via {@code <System Audio Mode Request>}.</li>
@@ -13678,13 +13683,6 @@
                 "angle_gl_driver_selection_values";
 
         /**
-         * List of package names that should check ANGLE rules
-         * @hide
-         */
-        @Readable
-        public static final String ANGLE_ALLOWLIST = "angle_allowlist";
-
-        /**
          * Lists of ANGLE EGL features for debugging.
          * Each list of features is separated by a comma, each feature in each list is separated by
          * a colon.
@@ -14332,8 +14330,11 @@
                 "are_user_disabled_hdr_formats_allowed";
 
         /**
-         * Whether or not syncs (bulk set operations) for {@link DeviceConfig} are disabled
-         * currently. The value is boolean (1 or 0). The value '1' means that {@link
+         * Whether or not syncs (bulk set operations) for {@link DeviceConfig} are currently
+         * persistently disabled. This is only used for the {@link
+         * Config#SYNC_DISABLED_MODE_PERSISTENT persistent} mode, {@link
+         * Config#SYNC_DISABLED_MODE_UNTIL_REBOOT until_reboot} mode is not stored in settings.
+         * The value is boolean (1 or 0). The value '1' means that {@link
          * DeviceConfig#setProperties(DeviceConfig.Properties)} will return {@code false}.
          *
          * @hide
@@ -14906,6 +14907,33 @@
                 "max_sound_trigger_detection_service_ops_per_day";
 
         /**
+         * Setting indicating the name of the Wear OS app package containing the device's sysui.
+         *
+         * @hide
+         */
+        public static final String CLOCKWORK_SYSUI_PACKAGE_NAME =
+                "clockwork_sysui_package_name";
+
+        /**
+         * Setting indicating the name of the main activity of the Wear OS sysui.
+         *
+         * @hide
+         */
+        public static final String CLOCKWORK_SYSUI_MAIN_ACTIVITY_NAME =
+                "clockwork_sysui_main_activity_name";
+
+        /**
+         * Setting to determine if the Clockwork Home application is ready.
+         *
+         * <p>
+         * Set to 1 when the Clockwork Home application has finished starting up.
+         * </p>
+         *
+         * @hide
+         */
+        public static final String CLOCKWORK_HOME_READY = "clockwork_home_ready";
+
+        /**
          * Indicates whether aware is available in the current location.
          * @hide
          */
@@ -14964,6 +14992,15 @@
         public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side";
 
         /**
+         * Global settings that shouldn't be persisted.
+         *
+         * @hide
+         */
+        public static final String[] TRANSIENT_SETTINGS = {
+                CLOCKWORK_HOME_READY,
+        };
+
+        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
@@ -16166,6 +16203,316 @@
          * @hide
          */
         public static final String RESTRICTED_NETWORKING_MODE = "restricted_networking_mode";
+
+        /**
+         * Settings migrated from Wear OS settings provider.
+         * @hide
+         */
+        public static class Wearable {
+            /**
+             * Whether the user has any pay tokens on their watch.
+             * @hide
+             */
+            public static final String HAS_PAY_TOKENS = "has_pay_tokens";
+
+            /**
+             * Gcm checkin timeout in minutes.
+             * @hide
+             */
+            public static final String GMS_CHECKIN_TIMEOUT_MIN = "gms_checkin_timeout_min";
+
+            /**
+             * If hotword detection should be enabled.
+             * @hide
+             */
+            public static final String HOTWORD_DETECTION_ENABLED = "hotword_detection_enabled";
+
+            /**
+             * Whether Smart Replies are enabled within Wear.
+             * @hide
+             */
+            public static final String SMART_REPLIES_ENABLED = "smart_replies_enabled";
+
+            /**
+             * The default vibration pattern.
+             * @hide
+             */
+            public static final String DEFAULT_VIBRATION = "default_vibration";
+
+            /**
+             * If FLP should obtain location data from the paired device.
+             * @hide
+             */
+            public static final String OBTAIN_PAIRED_DEVICE_LOCATION =
+                    "obtain_paired_device_location";
+
+            /**
+             * Whether the device is in retail mode.
+             * @hide
+             */
+            public static final String RETAIL_MODE = "retail_mode";
+
+            // Possible retail mode states
+            /** @hide */
+            public static final int RETAIL_MODE_CONSUMER = 0;
+            /** @hide */
+            public static final int RETAIL_MODE_RETAIL = 1;
+
+            /**
+             * The play store availability.
+             * @hide
+             */
+            public static final String PLAY_STORE_AVAILABILITY = "play_store_availability";
+
+            // Possible play store availability states
+            /** @hide */
+            public static final int PLAY_STORE_AVAILABILITY_UNKNOWN = 0;
+            /** @hide */
+            public static final int PLAY_STORE_AVAILABLE = 1;
+            /** @hide */
+            public static final int PLAY_STORE_UNAVAILABLE = 2;
+
+            /**
+             * Whether the bug report is enabled.
+             * @hide
+             */
+            public static final String BUG_REPORT = "bug_report";
+
+            // Possible bug report states
+            /** @hide */
+            public static final int BUG_REPORT_DISABLED = 0;
+            /** @hide */
+            public static final int BUG_REPORT_ENABLED = 1;
+
+            /**
+             * The enabled/disabled state of the SmartIlluminate.
+             * @hide
+             */
+            public static final String SMART_ILLUMINATE_ENABLED = "smart_illuminate_enabled";
+
+            /**
+             * Whether automatic time is enabled on the watch.
+             * @hide
+             */
+            public static final String CLOCKWORK_AUTO_TIME = "clockwork_auto_time";
+
+            // Possible clockwork auto time states
+            /** @hide */
+            public static final int SYNC_TIME_FROM_PHONE = 0;
+            /** @hide */
+            public static final int SYNC_TIME_FROM_NETWORK = 1;
+            /** @hide */
+            public static final int AUTO_TIME_OFF = 2;
+            /** @hide */
+            public static final int INVALID_AUTO_TIME_STATE = 3;
+
+
+            /**
+             * Whether automatic time zone is enabled on the watch.
+             * @hide
+             */
+            public static final String CLOCKWORK_AUTO_TIME_ZONE = "clockwork_auto_time_zone";
+
+            // Possible clockwork auto time zone states
+            /** @hide */
+            public static final int SYNC_TIME_ZONE_FROM_PHONE = 0;
+            /** @hide */
+            public static final int SYNC_TIME_ZONE_FROM_NETWORK = 1;
+            /** @hide */
+            public static final int AUTO_TIME_ZONE_OFF = 2;
+            /** @hide */
+            public static final int INVALID_AUTO_TIME_ZONE_STATE = 3;
+
+            /**
+             * Whether 24 hour time format is enabled on the watch.
+             * @hide
+             */
+            public static final String CLOCKWORK_24HR_TIME = "clockwork_24hr_time";
+
+            /**
+             * Whether the auto wifi toggle setting is enabled.
+             * @hide
+             */
+            public static final String AUTO_WIFI = "auto_wifi";
+
+            // Possible force wifi on states
+            /** @hide */
+            public static final int AUTO_WIFI_DISABLED = 0;
+            /** @hide */
+            public static final int AUTO_WIFI_ENABLED = 1;
+
+            /**
+             * The number of minutes after the WiFi enters power save mode.
+             * @hide
+             */
+            public static final String WIFI_POWER_SAVE = "wifi_power_save";
+
+            /**
+             * The time at which we should no longer skip the wifi requirement check (we skip the
+             * wifi requirement until this time). The time is in millis since epoch.
+             * @hide
+             */
+            public static final String ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS =
+                    "alt_bypass_wifi_requirement_time_millis";
+
+            /**
+             * Whether or not Up/Down Gestures are enabled.
+             * @hide
+             */
+            public static final String UPDOWN_GESTURES_ENABLED = "updown_gestures_enabled";
+
+            /**
+             * Whether the setup was skipped.
+             * @hide
+             */
+            public static final String SETUP_SKIPPED = "setup_skipped";
+
+            // Possible setup_skipped states
+            /** @hide */
+            public static final int SETUP_SKIPPED_UNKNOWN = 0;
+            /** @hide */
+            public static final int SETUP_SKIPPED_YES = 1;
+            /** @hide */
+            public static final int SETUP_SKIPPED_NO = 2;
+
+            /**
+             * The last requested call forwarding action.
+             * @hide
+             */
+            public static final String LAST_CALL_FORWARD_ACTION = "last_call_forward_action";
+
+            // Possible call forwarding actions
+            /** @hide */
+            public static final int CALL_FORWARD_ACTION_ON = 1;
+            /** @hide */
+            public static final int CALL_FORWARD_ACTION_OFF = 2;
+            /** @hide */
+            public static final int CALL_FORWARD_NO_LAST_ACTION = -1;
+
+            // Stem button settings.
+            /** @hide */
+            public static final String STEM_1_TYPE = "STEM_1_TYPE";
+            /** @hide */
+            public static final String STEM_1_DATA = "STEM_1_DATA";
+            /** @hide */
+            public static final String STEM_1_DEFAULT_DATA = "STEM_1_DEFAULT_DATA";
+            /** @hide */
+            public static final String STEM_2_TYPE = "STEM_2_TYPE";
+            /** @hide */
+            public static final String STEM_2_DATA = "STEM_2_DATA";
+            /** @hide */
+            public static final String STEM_2_DEFAULT_DATA = "STEM_2_DEFAULT_DATA";
+            /** @hide */
+            public static final String STEM_3_TYPE = "STEM_3_TYPE";
+            /** @hide */
+            public static final String STEM_3_DATA = "STEM_3_DATA";
+            /** @hide */
+            public static final String STEM_3_DEFAULT_DATA = "STEM_3_DEFAULT_DATA";
+
+            // Stem types
+            /** @hide */
+            public static final int STEM_TYPE_UNKNOWN = -1;
+            /** @hide */
+            public static final int STEM_TYPE_APP_LAUNCH = 0;
+            /** @hide */
+            public static final int STEM_TYPE_CONTACT_LAUNCH = 1;
+
+            /**
+             * If the device should be muted when off body.
+             * @hide
+             */
+            public static final String MUTE_WHEN_OFF_BODY_ENABLED = "obtain_mute_when_off_body";
+
+            /**
+             * Wear OS version string.
+             * @hide
+             */
+            public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string";
+
+            /**
+             * If an alternate launcher is enabled.
+             * @hide
+             */
+            public static final String ALTERNATE_LAUNCHER_ENABLED = "alternate_launcher_enabled";
+
+            /**
+             * How round the corners of square screens are.
+             * @hide
+             */
+            public static final String CORNER_ROUNDNESS = "corner_roundness";
+
+            /**
+             * Whether the physical button has been set.
+             * @hide
+             */
+            public static final String BUTTON_SET = "button_set";
+
+            /**
+             * Whether there is a side button.
+             * @hide
+             */
+            public static final String SIDE_BUTTON = "side_button";
+
+            /**
+             * The android wear system version.
+             * @hide
+             */
+            public static final String ANDROID_WEAR_VERSION = "android_wear_version";
+
+            /**
+             * The wear system capabiltiies.
+             * @hide
+             */
+            public static final String SYSTEM_CAPABILITIES = "system_capabilities";
+
+            /**
+             * The android wear system edition.
+             * @hide
+             */
+            public static final String SYSTEM_EDITION = "android_wear_system_edition";
+
+            /**
+             * The Wear platform MR number.
+             * @hide
+             */
+            public static final String WEAR_PLATFORM_MR_NUMBER = "wear_platform_mr_number";
+
+            /**
+             * The bluetooth settings storing duplicate address of companion device.
+             * @hide
+             */
+            public static final String COMPANION_BT_ADDRESS_DUAL = "companion_bt_address_dual";
+
+            /**
+             * The offset of the visible screen from the display bottom (overscan bottom).
+             * @hide
+             */
+            public static final String BOTTOM_OFFSET = "bottom_offset";
+
+            /**
+             * The shape of the display.
+             * @hide
+             */
+            public static final String DISPLAY_SHAPE = "display_shape";
+
+            // Possible display shapes
+            /** @hide */
+            public static final int DISPLAY_SHAPE_SQUARE = 0;
+            /** @hide */
+            public static final int DISPLAY_SHAPE_ROUND = 1;
+
+            /**
+             * The different levels of screen brightness the user can select.
+             * @hide
+             */
+            public static final String SCREEN_BRIGHTNESS_LEVEL = "screen_brightness_level";
+
+            /**
+             * The mobile signal detector setting.
+             * @hide
+             */
+            public static final String MOBILE_SIGNAL_DETECTOR = "mobile_signal_detector";
+        }
     }
 
     /**
@@ -16358,47 +16705,47 @@
         }
 
         /**
-         * Bridge method between {@link DeviceConfig#setSyncDisabled(int)} and the
+         * Bridge method between {@link DeviceConfig#setSyncDisabledMode(int)} and the
          * {@link com.android.providers.settings.SettingsProvider} implementation.
          *
          * @hide
          */
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
-        static void setSyncDisabled(
+        static void setSyncDisabledMode(
                 @NonNull ContentResolver resolver, @SyncDisabledMode int disableSyncMode) {
             try {
                 Bundle args = new Bundle();
                 args.putInt(CALL_METHOD_SYNC_DISABLED_MODE_KEY, disableSyncMode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getAttributionSource(),
-                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_SET_SYNC_DISABLED_CONFIG,
-                        null, args);
+                cp.call(resolver.getAttributionSource(), sProviderHolder.mUri.getAuthority(),
+                        CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG, null, args);
             } catch (RemoteException e) {
-                Log.w(TAG, "Can't set sync disabled " + DeviceConfig.CONTENT_URI, e);
+                Log.w(TAG, "Can't set sync disabled mode " + DeviceConfig.CONTENT_URI, e);
             }
         }
 
         /**
-         * Bridge method between {@link DeviceConfig#isSyncDisabled()} and the
+         * Bridge method between {@link DeviceConfig#getSyncDisabledMode()} and the
          * {@link com.android.providers.settings.SettingsProvider} implementation.
          *
          * @hide
          */
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
-        static boolean isSyncDisabled(@NonNull ContentResolver resolver) {
+        static int getSyncDisabledMode(@NonNull ContentResolver resolver) {
             try {
                 Bundle args = Bundle.EMPTY;
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
                 Bundle bundle = cp.call(resolver.getAttributionSource(),
-                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_IS_SYNC_DISABLED_CONFIG,
+                        sProviderHolder.mUri.getAuthority(),
+                        CALL_METHOD_GET_SYNC_DISABLED_MODE_CONFIG,
                         null, args);
-                return bundle.getBoolean(KEY_CONFIG_IS_SYNC_DISABLED_RETURN);
+                return bundle.getInt(KEY_CONFIG_GET_SYNC_DISABLED_MODE_RETURN);
             } catch (RemoteException e) {
-                Log.w(TAG, "Can't query sync disabled " + DeviceConfig.CONTENT_URI, e);
+                Log.w(TAG, "Can't query sync disabled mode " + DeviceConfig.CONTENT_URI, e);
             }
-            return false;
+            return -1;
         }
 
         /**
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f3a8b5d..387fc39 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5343,6 +5343,13 @@
         public static final String COLUMN_RCS_CONFIG = "rcs_config";
 
         /**
+         * TelephonyProvider column name for device to device sharing status.
+         *
+         * @hide
+         */
+        public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status";
+
+        /**
          * TelephonyProvider column name for VoIMS provisioning. Default is 0.
          * <P>Type: INTEGER </P>
          *
@@ -5351,13 +5358,6 @@
         public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status";
 
         /**
-         * TelephonyProvider column name for device to device sharing status.
-         *
-         * @hide
-         */
-        public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status";
-
-        /**
          * TelephonyProvider column name for information selected contacts that allow device to
          * device sharing.
          *
@@ -5365,5 +5365,6 @@
          */
         public static final String COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS =
                 "d2d_sharing_contacts";
+
     }
 }
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 62becc5..af846b6 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -96,6 +96,8 @@
      */
     public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10;
 
+    // The flag value 0x20 has been defined in AutofillManager.
+
     /** @hide */
     public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
 
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 4fd36e5..91042bfa 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -91,7 +91,8 @@
             = "android.service.notification.NotificationAssistantService";
 
     /**
-     * Data type: int, the feedback rating score provided by user
+     * Data type: int, the feedback rating score provided by user. The score can be any integer
+     *            value depends on the experimental and feedback UX design.
      */
     public static final String FEEDBACK_RATING = "feedback.rating";
 
@@ -129,7 +130,8 @@
      * A notification was posted by an app. Called before post.
      *
      * <p>Note: this method is only called if you don't override
-     * {@link #onNotificationEnqueued(StatusBarNotification, NotificationChannel)}.</p>
+     * {@link #onNotificationEnqueued(StatusBarNotification, NotificationChannel)} or
+     * {@link #onNotificationEnqueued(StatusBarNotification, NotificationChannel, RankingMap)}.</p>
      *
      * @param sbn the new notification
      * @return an adjustment or null to take no action, within 200ms.
@@ -139,6 +141,9 @@
     /**
      * A notification was posted by an app. Called before post.
      *
+     * <p>Note: this method is only called if you don't override
+     * {@link #onNotificationEnqueued(StatusBarNotification, NotificationChannel, RankingMap)}.</p>
+     *
      * @param sbn the new notification
      * @param channel the channel the notification was posted to
      * @return an adjustment or null to take no action, within 200ms.
@@ -282,7 +287,7 @@
      * @param key the notification key
      * @param rankingMap The current ranking map that can be used to retrieve ranking information
      *                   for active notifications.
-     * @param feedback the feedback detail
+     * @param feedback the received feedback, such as {@link #FEEDBACK_RATING rating score}
      */
     public void onNotificationFeedbackReceived(@NonNull String key, @NonNull RankingMap rankingMap,
             @NonNull Bundle feedback) {
diff --git a/core/java/android/service/notification/ScheduleCalendar.java b/core/java/android/service/notification/ScheduleCalendar.java
index 314c97d..1e5ff3a 100644
--- a/core/java/android/service/notification/ScheduleCalendar.java
+++ b/core/java/android/service/notification/ScheduleCalendar.java
@@ -20,6 +20,8 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.Calendar;
 import java.util.Objects;
 import java.util.TimeZone;
@@ -92,16 +94,22 @@
      */
     public long getNextChangeTime(long now) {
         if (mSchedule == null) return 0;
-        final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
-        final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute);
+        final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute, true);
+        final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute, false);
         long nextScheduleTime = Math.min(nextStart, nextEnd);
 
         return nextScheduleTime;
     }
 
-    private long getNextTime(long now, int hr, int min) {
-        final long time = getTime(now, hr, min);
-        return time <= now ? addDays(time, 1) : time;
+    private long getNextTime(long now, int hr, int min, boolean adjust) {
+        // The adjust parameter indicates whether to potentially adjust the time to the closest
+        // actual time if the indicated time is one skipped due to daylight time.
+        final long time = adjust ? getClosestActualTime(now, hr, min) : getTime(now, hr, min);
+        if (time <= now) {
+            final long tomorrow = addDays(time, 1);
+            return adjust ? getClosestActualTime(tomorrow, hr, min) : getTime(tomorrow, hr, min);
+        }
+        return time;
     }
 
     private long getTime(long millis, int hour, int min) {
@@ -119,7 +127,7 @@
      */
     public boolean isInSchedule(long time) {
         if (mSchedule == null || mDays.size() == 0) return false;
-        final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
+        final long start = getClosestActualTime(time, mSchedule.startHour, mSchedule.startMinute);
         long end = getTime(time, mSchedule.endHour, mSchedule.endMinute);
         if (end <= start) {
             end = addDays(end, 1);
@@ -134,7 +142,7 @@
      */
     public boolean isAlarmInSchedule(long alarm, long now) {
         if (mSchedule == null || mDays.size() == 0) return false;
-        final long start = getTime(alarm, mSchedule.startHour, mSchedule.startMinute);
+        final long start = getClosestActualTime(alarm, mSchedule.startHour, mSchedule.startMinute);
         long end = getTime(alarm, mSchedule.endHour, mSchedule.endMinute);
         if (end <= start) {
             end = addDays(end, 1);
@@ -186,4 +194,41 @@
         mCalendar.add(Calendar.DATE, days);
         return mCalendar.getTimeInMillis();
     }
+
+    /**
+     * This function returns the closest "actual" time to the provided hour/minute relative to the
+     * reference time. For most times this will behave exactly the same as getTime, but for any time
+     * during the hour skipped forward for daylight savings time (for instance, 02:xx when the
+     * clock is set to 03:00 after 01:59), this method will return the time when the clock changes
+     * (in this example, 03:00).
+     *
+     * Assumptions made in this implementation:
+     *   - Time is moved forward on an hour boundary (minute 0) by exactly 1hr when clocks shift
+     *   - a lenient Calendar implementation will interpret 02:xx on a day when 2-3AM is skipped
+     *     as 03:xx
+     *   - The skipped hour is never 11PM / 23:00.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public long getClosestActualTime(long refTime, int hour, int min) {
+        long resTime = getTime(refTime, hour, min);
+        if (!mCalendar.getTimeZone().observesDaylightTime()) {
+            // Do nothing if the timezone doesn't observe daylight time at all.
+            return resTime;
+        }
+
+        // Approach to identifying whether the time is "skipped": get the result from starting with
+        // refTime and setting hour and minute, then re-extract the hour and minute of the resulting
+        // moment in time. If the hour is exactly one more than the passed-in hour and the minute is
+        // the same, then the provided hour is likely a skipped one. If the time doesn't fall into
+        // this category, return the unmodified time instead.
+        mCalendar.setTimeInMillis(resTime);
+        int resHr = mCalendar.get(Calendar.HOUR_OF_DAY);
+        int resMin = mCalendar.get(Calendar.MINUTE);
+        if (resHr == hour + 1 && resMin == min) {
+            return getTime(refTime, resHr, 0);
+        }
+        return resTime;
+    }
 }
diff --git a/core/java/android/service/timezone/TimeZoneProviderService.java b/core/java/android/service/timezone/TimeZoneProviderService.java
index a2b22e8..b516b02 100644
--- a/core/java/android/service/timezone/TimeZoneProviderService.java
+++ b/core/java/android/service/timezone/TimeZoneProviderService.java
@@ -114,9 +114,15 @@
  *
  * <p>Threading:
  *
- * <p>Calls to {@code report} methods can be made on on any thread and will be passed asynchronously
- * to the system server. Calls to {@link #onStartUpdates(long)} and {@link #onStopUpdates()} will
- * occur on a single thread.
+ * <p>Outgoing calls to {@code report} methods can be made on any thread and will be delivered
+ * asynchronously to the system server. Incoming calls to {@link TimeZoneProviderService}-defined
+ * service methods like {@link #onStartUpdates(long)} and {@link #onStopUpdates()} are also
+ * asynchronous with respect to the system server caller and will be delivered to this service using
+ * a single thread. {@link Service} lifecycle method calls like {@link #onCreate()} and {@link
+ * #onDestroy()} can occur on a different thread from those made to {@link
+ * TimeZoneProviderService}-defined service methods, so implementations must be defensive and not
+ * assume an ordering between them, e.g. a call to {@link #onStopUpdates()} can occur after {@link
+ * #onDestroy()} and should be handled safely.
  *
  * @hide
  */
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 696271c..f0ce325 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -23,10 +23,10 @@
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
-import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Build;
 import android.os.Trace;
@@ -65,7 +65,7 @@
      *
      * @throws PackageParserException if the APK's signature failed to verify.
      */
-    public static PackageParser.SigningDetails verify(String apkPath,
+    public static SigningDetails verify(String apkPath,
             @SignatureSchemeVersion int minSignatureSchemeVersion)
             throws PackageParserException {
         return verifySignatures(apkPath, minSignatureSchemeVersion, true);
@@ -78,7 +78,7 @@
      *
      * @throws PackageParserException if there was a problem collecting certificates.
      */
-    public static PackageParser.SigningDetails unsafeGetCertsWithoutVerification(
+    public static SigningDetails unsafeGetCertsWithoutVerification(
             String apkPath, int minSignatureSchemeVersion)
             throws PackageParserException {
         return verifySignatures(apkPath, minSignatureSchemeVersion, false);
@@ -90,7 +90,7 @@
      * @param verifyFull whether to verify all contents of this APK or just collect certificates.
      * @throws PackageParserException if there was a problem collecting certificates
      */
-    private static PackageParser.SigningDetails verifySignatures(String apkPath,
+    private static SigningDetails verifySignatures(String apkPath,
             @SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
             throws PackageParserException {
         return verifySignaturesInternal(apkPath, minSignatureSchemeVersion,
@@ -249,7 +249,7 @@
                 }
             }
 
-            return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+            return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
                     SignatureSchemeVersion.SIGNING_BLOCK_V4), vSigner.contentDigests);
         } catch (SignatureNotFoundException e) {
             throw e;
@@ -290,7 +290,7 @@
                     pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
                 }
             }
-            return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+            return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
                     SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs),
                     vSigner.contentDigests);
         } catch (SignatureNotFoundException e) {
@@ -321,7 +321,7 @@
                     ApkSignatureSchemeV2Verifier.verify(apkPath, verifyFull);
             Certificate[][] signerCerts = vSigner.certs;
             Signature[] signerSigs = convertToSignatures(signerCerts);
-            return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs,
+            return new SigningDetailsWithDigests(new SigningDetails(signerSigs,
                     SignatureSchemeVersion.SIGNING_BLOCK_V2), vSigner.contentDigests);
         } catch (SignatureNotFoundException e) {
             throw e;
@@ -408,7 +408,7 @@
                 }
             }
             return new SigningDetailsWithDigests(
-                    new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR), null);
+                    new SigningDetails(lastSigs, SignatureSchemeVersion.JAR), null);
         } catch (GeneralSecurityException e) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
                     "Failed to collect certificates from " + apkPath, e);
@@ -565,7 +565,7 @@
      * @hide for internal use only.
      */
     public static class SigningDetailsWithDigests {
-        public final PackageParser.SigningDetails signingDetails;
+        public final SigningDetails signingDetails;
 
         /**
          * APK Signature Schemes v2/v3/v4 might contain multiple content digests.
@@ -576,7 +576,7 @@
          */
         public final Map<Integer, byte[]> contentDigests;
 
-        SigningDetailsWithDigests(PackageParser.SigningDetails signingDetails,
+        SigningDetailsWithDigests(SigningDetails signingDetails,
                 Map<Integer, byte[]> contentDigests) {
             this.signingDetails = signingDetails;
             this.contentDigests = contentDigests;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8021636..305cb97 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -865,4 +865,11 @@
     void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
 
     boolean isTaskSnapshotSupported();
+
+    /**
+     * Returns the preferred display ID to show software keyboard.
+     *
+     * @see android.window.WindowProviderService#getLaunchedDisplayId
+     */
+    int getImeDisplayId();
 }
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 5a34a92..bd97ef0 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import static android.view.Display.INVALID_DISPLAY;
-
 import android.annotation.Nullable;
 import android.graphics.Region;
+import android.gui.TouchOcclusionMode;
 import android.os.IBinder;
-import android.os.TouchOcclusionMode;
 
 import java.lang.ref.WeakReference;
 
@@ -101,10 +99,6 @@
     // Display this input is on.
     public int displayId;
 
-    // If this value is set to a valid display ID, it indicates this window is a portal which
-    // transports the touch of this window to the display indicated by portalToDisplayId.
-    public int portalToDisplayId = INVALID_DISPLAY;
-
     /**
      * Crops the touchable region to the bounds of the surface provided.
      *
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0483d0b..11b5a06 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3999,6 +3999,22 @@
         public float orientation;
 
         /**
+         * The movement of x position of a motion event.
+         *
+         * @see MotionEvent#AXIS_RELATIVE_X
+         * @hide
+         */
+        public float relativeX;
+
+        /**
+         * The movement of y position of a motion event.
+         *
+         * @see MotionEvent#AXIS_RELATIVE_Y
+         * @hide
+         */
+        public float relativeY;
+
+        /**
          * Clears the contents of this object.
          * Resets all axes to zero.
          */
@@ -4014,6 +4030,8 @@
             toolMajor = 0;
             toolMinor = 0;
             orientation = 0;
+            relativeX = 0;
+            relativeY = 0;
         }
 
         /**
@@ -4044,6 +4062,8 @@
             toolMajor = other.toolMajor;
             toolMinor = other.toolMinor;
             orientation = other.orientation;
+            relativeX = other.relativeX;
+            relativeY = other.relativeY;
         }
 
         /**
@@ -4075,6 +4095,10 @@
                     return toolMinor;
                 case AXIS_ORIENTATION:
                     return orientation;
+                case AXIS_RELATIVE_X:
+                    return relativeX;
+                case AXIS_RELATIVE_Y:
+                    return relativeY;
                 default: {
                     if (axis < 0 || axis > 63) {
                         throw new IllegalArgumentException("Axis out of range.");
@@ -4128,6 +4152,12 @@
                 case AXIS_ORIENTATION:
                     orientation = value;
                     break;
+                case AXIS_RELATIVE_X:
+                    relativeX = value;
+                    break;
+                case AXIS_RELATIVE_Y:
+                    relativeY = value;
+                    break;
                 default: {
                     if (axis < 0 || axis > 63) {
                         throw new IllegalArgumentException("Axis out of range.");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index c03db6d..1d8eb5e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -162,6 +162,8 @@
             IBinder displayToken, long nativeSurfaceObject);
     private static native void nativeSetDisplayLayerStack(long transactionObj,
             IBinder displayToken, int layerStack);
+    private static native void nativeSetDisplayFlags(long transactionObj,
+            IBinder displayToken, int flags);
     private static native void nativeSetDisplayProjection(long transactionObj,
             IBinder displayToken, int orientation,
             int l, int t, int r, int b,
@@ -547,6 +549,15 @@
      */
     private static final int SURFACE_OPAQUE = 0x02;
 
+    /* flags used with setDisplayFlags() (keep in sync with DisplayDevice.h) */
+
+    /**
+     * DisplayDevice flag: This display's transform is sent to inputflinger and used for input
+     * dispatch. This flag is used to disambiguate displays which share a layerstack.
+     * @hide
+     */
+    public static final int DISPLAY_RECEIVES_INPUT = 0x01;
+
     // Display power modes.
     /**
      * Display power mode off: used while blanking the screen.
@@ -3169,6 +3180,17 @@
         /**
          * @hide
          */
+        public Transaction setDisplayFlags(IBinder displayToken, int flags) {
+            if (displayToken == null) {
+                throw new IllegalArgumentException("displayToken must not be null");
+            }
+            nativeSetDisplayFlags(mNativeObject, displayToken, flags);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
         public Transaction setDisplayProjection(IBinder displayToken,
                 int orientation, Rect layerStackRect, Rect displayRect) {
             if (displayToken == null) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4f2cf6d..f04530f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1559,12 +1559,21 @@
      * @hide
      */
     public void setResizeBackgroundColor(int bgColor) {
+        setResizeBackgroundColor(mTmpTransaction, bgColor);
+        mTmpTransaction.apply();
+    }
+
+    /**
+     * Version of {@link #setResizeBackgroundColor(int)} that allows you to provide
+     * {@link SurfaceControl.Transaction}.
+     * @hide
+     */
+    public void setResizeBackgroundColor(@NonNull SurfaceControl.Transaction t, int bgColor) {
         if (mBackgroundControl == null) {
             return;
         }
-
         mBackgroundColor = bgColor;
-        updateBackgroundColor(mTmpTransaction).apply();
+        updateBackgroundColor(t);
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9450801..1793eaf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6432,7 +6432,7 @@
 
     @Override
     public String toString() {
-        StringBuilder out = new StringBuilder(128);
+        StringBuilder out = new StringBuilder(256);
         out.append(getClass().getName());
         out.append('{');
         out.append(Integer.toHexString(System.identityHashCode(this)));
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 679da31..488f7c3 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2723,7 +2723,7 @@
                                     continue;
                                 }
                                 childWithAccessibilityFocus = null;
-                                i = childrenCount - 1;
+                                i = childrenCount;
                             }
 
                             if (!child.canReceivePointerEvents()
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5a248af..8d4116a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -284,6 +284,21 @@
      */
     private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
 
+    /**
+     * If set to {@code true}, the new logic to layout system bars as normal window and to use
+     * layout result to get insets will be applied. Otherwise, the old hard-coded window logic will
+     * be applied.
+     */
+    private static final String USE_FLEXIBLE_INSETS = "persist.debug.flexible_insets";
+
+    /**
+     * A flag to indicate to use the new generalized insets window logic, or the old hard-coded
+     * insets window layout logic.
+     * {@hide}
+     */
+    public static final boolean INSETS_LAYOUT_GENERALIZATION =
+            SystemProperties.getBoolean(USE_FLEXIBLE_INSETS, false);
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
@@ -9146,15 +9161,26 @@
             return;
         }
 
-        // We only care about change types that may affect the bounds of the
-        // focused virtual view.
+        final long eventSourceNodeId = event.getSourceNodeId();
+        final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
+
+        // Only change types that may affect the bounds of the focused virtual view should run
+        // the update bounds logic after this if block.
         final int changes = event.getContentChangeTypes();
         if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
                 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
+            // Now the changes(text, content description, state description) are local to this node.
+            // If the focused virtual view changed, we need to update the
+            // mAccessibilityFocusedVirtualView, otherwise A11y services will get stale value.
+            if (eventSourceNodeId == focusedSourceNodeId) {
+                int focusedChildId =
+                        AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
+                mAccessibilityFocusedVirtualView =
+                        provider.createAccessibilityNodeInfo(focusedChildId);
+            }
             return;
         }
 
-        final long eventSourceNodeId = event.getSourceNodeId();
         final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
 
         // Search up the tree for subtree containment.
@@ -9178,7 +9204,6 @@
             return;
         }
 
-        final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
         int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
 
         // Refresh the node for the focused virtual view.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2996c3d..63a4ad4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -97,6 +97,7 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -394,6 +395,11 @@
      */
     int TRANSIT_KEYGUARD_UNOCCLUDE = 9;
     /**
+     * A window is starting to enter PiP.
+     * @hide
+     */
+    int TRANSIT_PIP = 10;
+    /**
      * The first slot for custom transition types. Callers (like Shell) can make use of custom
      * transition types for dealing with special cases. These types are effectively ignored by
      * Core and will just be passed along as part of TransitionInfo objects. An example is
@@ -402,7 +408,7 @@
      * implementation.
      * @hide
      */
-    int TRANSIT_FIRST_CUSTOM = 10;
+    int TRANSIT_FIRST_CUSTOM = 11;
 
     /**
      * @hide
@@ -418,6 +424,7 @@
             TRANSIT_KEYGUARD_GOING_AWAY,
             TRANSIT_KEYGUARD_OCCLUDE,
             TRANSIT_KEYGUARD_UNOCCLUDE,
+            TRANSIT_PIP,
             TRANSIT_FIRST_CUSTOM
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -467,6 +474,13 @@
     int TRANSIT_FLAG_KEYGUARD_LOCKED = 0x40;
 
     /**
+     * Transition flag: Indicates that this transition is for recents animation.
+     * TODO(b/188669821): Remove once special-case logic moves to shell.
+     * @hide
+     */
+    int TRANSIT_FLAG_IS_RECENTS = 0x80;
+
+    /**
      * @hide
      */
     @IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -476,7 +490,8 @@
             TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
             TRANSIT_FLAG_APP_CRASHED,
             TRANSIT_FLAG_OPEN_BEHIND,
-            TRANSIT_FLAG_KEYGUARD_LOCKED
+            TRANSIT_FLAG_KEYGUARD_LOCKED,
+            TRANSIT_FLAG_IS_RECENTS
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionFlags {}
@@ -3460,6 +3475,22 @@
         public @InsetsState.InternalInsetsType int[] providesInsetsTypes;
 
         /**
+         * If specified, the insets provided by this window will be our window frame minus the
+         * insets specified by providedInternalInsets.
+         *
+         * @hide
+         */
+        public Insets providedInternalInsets = Insets.NONE;
+
+        /**
+         * {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
+         * This will make layout during rotation change smoothly.
+         *
+         * @hide
+         */
+        public LayoutParams[] paramsForRotation;
+
+        /**
          * Specifies types of insets that this window should avoid overlapping during layout.
          *
          * @param types which {@link WindowInsets.Type}s of insets that this window should avoid.
@@ -3558,6 +3589,18 @@
             return mFitInsetsIgnoringVisibility;
         }
 
+        private void checkNonRecursiveParams() {
+            if (paramsForRotation == null) {
+                return;
+            }
+            for (int i = paramsForRotation.length - 1; i >= 0; i--) {
+                if (paramsForRotation[i].paramsForRotation != null) {
+                    throw new IllegalArgumentException(
+                            "Params cannot contain params recursively.");
+                }
+            }
+        }
+
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = TYPE_APPLICATION;
@@ -3811,6 +3854,14 @@
             } else {
                 out.writeInt(0);
             }
+            providedInternalInsets.writeToParcel(out, 0 /* parcelableFlags */);
+            if (paramsForRotation != null) {
+                checkNonRecursiveParams();
+                out.writeInt(paramsForRotation.length);
+                out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
+            } else {
+                out.writeInt(0);
+            }
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -3881,6 +3932,12 @@
                 providesInsetsTypes = new int[insetsTypesLength];
                 in.readIntArray(providesInsetsTypes);
             }
+            providedInternalInsets = Insets.CREATOR.createFromParcel(in);
+            int paramsForRotationLength = in.readInt();
+            if (paramsForRotationLength > 0) {
+                paramsForRotation = new LayoutParams[paramsForRotationLength];
+                in.readTypedArray(paramsForRotation, LayoutParams.CREATOR);
+            }
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4170,6 +4227,17 @@
                 changes |= LAYOUT_CHANGED;
             }
 
+            if (!providedInternalInsets.equals(o.providedInternalInsets)) {
+                providedInternalInsets = o.providedInternalInsets;
+                changes |= LAYOUT_CHANGED;
+            }
+
+            if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) {
+                paramsForRotation = o.paramsForRotation;
+                checkNonRecursiveParams();
+                changes |= LAYOUT_CHANGED;
+            }
+
             return changes;
         }
 
@@ -4361,6 +4429,18 @@
                     sb.append(InsetsState.typeToString(providesInsetsTypes[i]));
                 }
             }
+            if (!providedInternalInsets.equals(Insets.NONE)) {
+                sb.append(" providedInternalInsets=");
+                sb.append(providedInternalInsets);
+            }
+            if (paramsForRotation != null && paramsForRotation.length != 0) {
+                sb.append(System.lineSeparator());
+                sb.append(prefix).append("  paramsForRotation=");
+                for (int i = 0; i < paramsForRotation.length; ++i) {
+                    if (i > 0) sb.append(' ');
+                    sb.append(paramsForRotation[i].toString());
+                }
+            }
 
             sb.append('}');
             return sb.toString();
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index f6d6fde..40da86a 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -1298,6 +1298,7 @@
         parcel.readList(record.mText, null);
         record.mSourceWindowId = parcel.readInt();
         record.mSourceNodeId = parcel.readLong();
+        record.mSourceDisplayId = parcel.readInt();
         record.mSealed = (parcel.readInt() == 1);
     }
 
@@ -1364,6 +1365,7 @@
         parcel.writeList(record.mText);
         parcel.writeInt(record.mSourceWindowId);
         parcel.writeLong(record.mSourceNodeId);
+        parcel.writeInt(record.mSourceDisplayId);
         parcel.writeInt(record.mSealed ? 1 : 0);
     }
 
@@ -1402,6 +1404,7 @@
             if (DEBUG) {
                 builder.append("; SourceWindowId: 0x").append(Long.toHexString(mSourceWindowId));
                 builder.append("; SourceNodeId: 0x").append(Long.toHexString(mSourceNodeId));
+                builder.append("; SourceDisplayId: ").append(mSourceDisplayId);
             }
             for (int i = 0; i < getRecordCount(); i++) {
                 builder.append("  Record ").append(i).append(":");
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 272dfac..8d49569 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -16,6 +16,9 @@
 
 package android.view.accessibility;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CLIENT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK;
+
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -86,6 +89,7 @@
     public static final int NO_ID = -1;
 
     public static final String CALL_STACK = "call_stack";
+    public static final String IGNORE_CALL_STACK = "ignore_call_stack";
 
     private static final String LOG_TAG = "AccessibilityInteractionClient";
 
@@ -121,6 +125,12 @@
 
     private volatile int mInteractionId = -1;
     private volatile int mCallingUid = Process.INVALID_UID;
+    // call stack for IAccessibilityInteractionConnectionCallback APIs. These callback APIs are
+    // shared by multiple requests APIs in IAccessibilityServiceConnection. To correctly log the
+    // request API which triggers the callback, we log trace entries for callback after the
+    // request API thread waiting for the callback returns. To log the correct callback stack in
+    // the request API thread, we save the callback stack in this member variables.
+    private List<StackTraceElement> mCallStackOfCallback;
 
     private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult;
 
@@ -307,18 +317,30 @@
                         if (DEBUG) {
                             Log.i(LOG_TAG, "Window cache hit");
                         }
+                        if (shouldTraceClient()) {
+                            logTraceClient(connection, "getWindow cache",
+                                    "connectionId=" + connectionId + ";accessibilityWindowId="
+                                    + accessibilityWindowId + ";bypassCache=false");
+                        }
                         return window;
                     }
                     if (DEBUG) {
                         Log.i(LOG_TAG, "Window cache miss");
                     }
                 }
+
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
                     window = connection.getWindow(accessibilityWindowId);
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "getWindow", "connectionId=" + connectionId
+                            + ";accessibilityWindowId=" + accessibilityWindowId + ";bypassCache="
+                            + bypassCache);
+                }
+
                 if (window != null) {
                     if (!bypassCache) {
                         sAccessibilityCache.addWindow(window);
@@ -368,6 +390,10 @@
                     if (DEBUG) {
                         Log.i(LOG_TAG, "Windows cache hit");
                     }
+                    if (shouldTraceClient()) {
+                        logTraceClient(
+                                connection, "getWindows cache", "connectionId=" + connectionId);
+                    }
                     return windows;
                 }
                 if (DEBUG) {
@@ -379,6 +405,9 @@
                 } finally {
                     Binder.restoreCallingIdentity(identityToken);
                 }
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "getWindows", "connectionId=" + connectionId);
+                }
                 if (windows != null) {
                     sAccessibilityCache.setWindowsOnAllDisplays(windows);
                     return windows;
@@ -472,6 +501,15 @@
                             Log.i(LOG_TAG, "Node cache hit for "
                                     + idToString(accessibilityWindowId, accessibilityNodeId));
                         }
+                        if (shouldTraceClient()) {
+                            logTraceClient(connection,
+                                    "findAccessibilityNodeInfoByAccessibilityId cache",
+                                    "connectionId=" + connectionId + ";accessibilityWindowId="
+                                    + accessibilityWindowId + ";accessibilityNodeId="
+                                    + accessibilityNodeId + ";bypassCache=" + bypassCache
+                                    + ";prefetchFlags=" + prefetchFlags + ";arguments="
+                                    + arguments);
+                        }
                         return cachedInfo;
                     }
                     if (DEBUG) {
@@ -488,6 +526,14 @@
                     prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
                 }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "findAccessibilityNodeInfoByAccessibilityId",
+                            "InteractionId:" + interactionId + "connectionId=" + connectionId
+                            + ";accessibilityWindowId=" + accessibilityWindowId
+                            + ";accessibilityNodeId=" + accessibilityNodeId + ";bypassCache="
+                            + bypassCache + ";prefetchFlags=" + prefetchFlags + ";arguments="
+                            + arguments);
+                }
                 final String[] packageNames;
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
@@ -500,16 +546,10 @@
                 if (packageNames != null) {
                     AccessibilityNodeInfo info =
                             getFindAccessibilityNodeInfoResultAndClear(interactionId);
-                    if (mAccessibilityManager != null
-                            && mAccessibilityManager.isAccessibilityTracingEnabled()) {
-                        logTrace(connection, "findAccessibilityNodeInfoByAccessibilityId",
-                                "InteractionId:" + interactionId + ";Result: " + info
-                                        + ";connectionId=" + connectionId
-                                        + ";accessibilityWindowId="
-                                        + accessibilityWindowId + ";accessibilityNodeId="
-                                        + accessibilityNodeId + ";bypassCache=" + bypassCache
-                                        + ";prefetchFlags=" + prefetchFlags
-                                        + ";arguments=" + arguments);
+                    if (shouldTraceCallback()) {
+                        logTraceCallback(connection, "findAccessibilityNodeInfoByAccessibilityId",
+                                "InteractionId:" + interactionId + ";connectionId="
+                                + connectionId + ";Result: " + info);
                     }
                     if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
                             && info != null) {
@@ -571,6 +611,14 @@
                 final String[] packageNames;
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
+                    if (shouldTraceClient()) {
+                        logTraceClient(connection, "findAccessibilityNodeInfosByViewId",
+                                "InteractionId=" + interactionId + ";connectionId=" + connectionId
+                                + ";accessibilityWindowId=" + accessibilityWindowId
+                                + ";accessibilityNodeId=" + accessibilityNodeId + ";viewId="
+                                + viewId);
+                    }
+
                     packageNames = connection.findAccessibilityNodeInfosByViewId(
                             accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
                             Thread.currentThread().getId());
@@ -581,13 +629,10 @@
                 if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    if (mAccessibilityManager != null
-                            && mAccessibilityManager.isAccessibilityTracingEnabled()) {
-                        logTrace(connection, "findAccessibilityNodeInfosByViewId", "InteractionId="
-                                + interactionId + ":Result: " + infos + ";connectionId="
-                                + connectionId + ";accessibilityWindowId=" + accessibilityWindowId
-                                + ";accessibilityNodeId=" + accessibilityNodeId + ";viewId="
-                                + viewId);
+                    if (shouldTraceCallback()) {
+                        logTraceCallback(connection, "findAccessibilityNodeInfosByViewId",
+                                "InteractionId=" + interactionId + ";connectionId=" + connectionId
+                                + ":Result: " + infos);
                     }
                     if (infos != null) {
                         finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
@@ -630,6 +675,12 @@
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "findAccessibilityNodeInfosByText",
+                            "InteractionId:" + interactionId + "connectionId=" + connectionId
+                            + ";accessibilityWindowId=" + accessibilityWindowId
+                            + ";accessibilityNodeId=" + accessibilityNodeId + ";text=" + text);
+                }
                 final String[] packageNames;
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
@@ -643,12 +694,10 @@
                 if (packageNames != null) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    if (mAccessibilityManager != null
-                            && mAccessibilityManager.isAccessibilityTracingEnabled()) {
-                        logTrace(connection, "findAccessibilityNodeInfosByText", "InteractionId="
-                                + interactionId + ":Result: " + infos + ";connectionId="
-                                + connectionId + ";accessibilityWindowId=" + accessibilityWindowId
-                                + ";accessibilityNodeId=" + accessibilityNodeId + ";text=" + text);
+                    if (shouldTraceCallback()) {
+                        logTraceCallback(connection, "findAccessibilityNodeInfosByText",
+                                "InteractionId=" + interactionId + ";connectionId=" + connectionId
+                                + ";Result: " + infos);
                     }
                     if (infos != null) {
                         finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
@@ -690,6 +739,13 @@
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "findFocus",
+                            "InteractionId:" + interactionId + "connectionId=" + connectionId
+                            + ";accessibilityWindowId=" + accessibilityWindowId
+                            + ";accessibilityNodeId=" + accessibilityNodeId + ";focusType="
+                            + focusType);
+                }
                 final String[] packageNames;
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
@@ -703,13 +759,9 @@
                 if (packageNames != null) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
-                    if (mAccessibilityManager != null
-                            && mAccessibilityManager.isAccessibilityTracingEnabled()) {
-                        logTrace(connection, "findFocus", "InteractionId=" + interactionId
-                                + ":Result: " + info + ";connectionId=" + connectionId
-                                + ";accessibilityWindowId=" + accessibilityWindowId
-                                + ";accessibilityNodeId=" + accessibilityNodeId + ";focusType="
-                                + focusType);
+                    if (shouldTraceCallback()) {
+                        logTraceCallback(connection, "findFocus", "InteractionId=" + interactionId
+                                + ";connectionId=" + connectionId + ";Result:" + info);
                     }
                     finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
                     return info;
@@ -747,6 +799,13 @@
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "focusSearch",
+                            "InteractionId:" + interactionId + "connectionId=" + connectionId
+                            + ";accessibilityWindowId=" + accessibilityWindowId
+                            + ";accessibilityNodeId=" + accessibilityNodeId + ";direction="
+                            + direction);
+                }
                 final String[] packageNames;
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
@@ -761,13 +820,9 @@
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
                     finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
-                    if (mAccessibilityManager != null
-                            && mAccessibilityManager.isAccessibilityTracingEnabled()) {
-                        logTrace(connection, "focusSearch", "InteractionId=" + interactionId
-                                + ":Result: " + info + ";connectionId=" + connectionId
-                                + ";accessibilityWindowId=" + accessibilityWindowId
-                                + ";accessibilityNodeId=" + accessibilityNodeId + ";direction="
-                                + direction);
+                    if (shouldTraceCallback()) {
+                        logTraceCallback(connection, "focusSearch", "InteractionId=" + interactionId
+                                + ";connectionId=" + connectionId + ";Result:" + info);
                     }
                     return info;
                 }
@@ -803,6 +858,13 @@
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
+                if (shouldTraceClient()) {
+                    logTraceClient(connection, "performAccessibilityAction",
+                            "InteractionId:" + interactionId + "connectionId=" + connectionId
+                            + ";accessibilityWindowId=" + accessibilityWindowId
+                            + ";accessibilityNodeId=" + accessibilityNodeId + ";action=" + action
+                            + ";arguments=" + arguments);
+                }
                 final boolean success;
                 final long identityToken = Binder.clearCallingIdentity();
                 try {
@@ -816,13 +878,10 @@
                 if (success) {
                     final boolean result =
                             getPerformAccessibilityActionResultAndClear(interactionId);
-                    if (mAccessibilityManager != null
-                            && mAccessibilityManager.isAccessibilityTracingEnabled()) {
-                        logTrace(connection, "performAccessibilityAction", "InteractionId="
-                                + interactionId + ":Result: " + result + ";connectionId="
-                                + connectionId + ";accessibilityWindowId=" + accessibilityWindowId
-                                + ";accessibilityNodeId=" + accessibilityNodeId + ";action="
-                                + action + ";arguments=" + arguments);
+                    if (shouldTraceCallback()) {
+                        logTraceCallback(connection, "performAccessibilityAction",
+                                "InteractionId=" + interactionId + ";connectionId=" + connectionId
+                                + ";Result: " + result);
                     }
                     return result;
                 }
@@ -883,6 +942,8 @@
                 mFindAccessibilityNodeInfoResult = info;
                 mInteractionId = interactionId;
                 mCallingUid = Binder.getCallingUid();
+                mCallStackOfCallback = new ArrayList<StackTraceElement>(
+                        Arrays.asList(Thread.currentThread().getStackTrace()));
             }
             mInstanceLock.notifyAll();
         }
@@ -933,6 +994,8 @@
                 }
                 mInteractionId = interactionId;
                 mCallingUid = Binder.getCallingUid();
+                mCallStackOfCallback = new ArrayList<StackTraceElement>(
+                    Arrays.asList(Thread.currentThread().getStackTrace()));
             }
             mInstanceLock.notifyAll();
         }
@@ -972,13 +1035,15 @@
             finalizeAndCacheAccessibilityNodeInfos(
                     infos, connectionIdWaitingForPrefetchResultCopy, false,
                     packageNamesForNextPrefetchResultCopy);
-            if (mAccessibilityManager != null
-                    && mAccessibilityManager.isAccessibilityTracingEnabled()) {
+            if (shouldTraceCallback()) {
                 logTrace(getConnection(connectionIdWaitingForPrefetchResultCopy),
                         "setPrefetchAccessibilityNodeInfoResult",
-                        "InteractionId:" + interactionId + ";Result: " + infos
-                                + ";connectionId=" + connectionIdWaitingForPrefetchResultCopy,
-                        Binder.getCallingUid());
+                        "InteractionId:" + interactionId + ";connectionId="
+                        + connectionIdWaitingForPrefetchResultCopy + ";Result: " + infos,
+                        Binder.getCallingUid(),
+                        Arrays.asList(Thread.currentThread().getStackTrace()),
+                        new HashSet<String>(Arrays.asList("getStackTrace")),
+                        FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK);
             }
         } else if (DEBUG) {
             Log.w(LOG_TAG, "Prefetching for interaction with id " + interactionId + " dropped "
@@ -1010,6 +1075,8 @@
                 mPerformAccessibilityActionResult = succeeded;
                 mInteractionId = interactionId;
                 mCallingUid = Binder.getCallingUid();
+                mCallStackOfCallback = new ArrayList<StackTraceElement>(
+                    Arrays.asList(Thread.currentThread().getStackTrace()));
             }
             mInstanceLock.notifyAll();
         }
@@ -1219,24 +1286,45 @@
         return true;
     }
 
+    private boolean shouldTraceClient() {
+        return (mAccessibilityManager != null)
+                && mAccessibilityManager.isA11yInteractionClientTraceEnabled();
+    }
+
+    private boolean shouldTraceCallback() {
+        return (mAccessibilityManager != null)
+                && mAccessibilityManager.isA11yInteractionConnectionCBTraceEnabled();
+    }
+
     private void logTrace(
             IAccessibilityServiceConnection connection, String method, String params,
-            int callingUid) {
+            int callingUid, List<StackTraceElement> callStack, HashSet<String> ignoreSet,
+            long logTypes) {
         try {
             Bundle b = new Bundle();
-            ArrayList<StackTraceElement> callStack = new ArrayList<StackTraceElement>(
-                    Arrays.asList(Thread.currentThread().getStackTrace()));
-            b.putSerializable(CALL_STACK, callStack);
+            b.putSerializable(CALL_STACK, new ArrayList<StackTraceElement>(callStack));
+            if (ignoreSet != null) {
+                b.putSerializable(IGNORE_CALL_STACK, ignoreSet);
+            }
             connection.logTrace(SystemClock.elapsedRealtimeNanos(),
-                    LOG_TAG + ".callback for " + method, params, Process.myPid(),
-                    Thread.currentThread().getId(), callingUid, b);
+                    LOG_TAG + "." + method,
+                    logTypes, params, Process.myPid(), Thread.currentThread().getId(),
+                    callingUid, b);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Failed to log trace. " + e);
         }
     }
 
-    private void logTrace(
+    private void logTraceCallback(
             IAccessibilityServiceConnection connection, String method, String params) {
-        logTrace(connection, method, params, mCallingUid);
+        logTrace(connection, method + " callback", params, mCallingUid, mCallStackOfCallback,
+                new HashSet<String>(Arrays.asList("getStackTrace")),
+                FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK);
+    }
+
+    private void logTraceClient(
+            IAccessibilityServiceConnection connection, String method, String params) {
+        logTrace(connection, method, params, Binder.getCallingUid(),
+                Collections.emptyList(), null, FLAGS_ACCESSIBILITY_INTERACTION_CLIENT);
     }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index f9cdbd3..17fad7e 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -111,7 +111,13 @@
     public static final int STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000010;
 
     /** @hide */
-    public static final int STATE_FLAG_ACCESSIBILITY_TRACING_ENABLED = 0x00000020;
+    public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED = 0x00000100;
+    /** @hide */
+    public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED = 0x00000200;
+    /** @hide */
+    public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED = 0x00000400;
+    /** @hide */
+    public static final int STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED = 0x00000800;
 
     /** @hide */
     public static final int DALTONIZER_DISABLED = -1;
@@ -235,8 +241,8 @@
     @UnsupportedAppUsage(trackingBug = 123768939L)
     boolean mIsHighTextContrastEnabled;
 
-    // Whether accessibility tracing is enabled or not
-    boolean mIsAccessibilityTracingEnabled = false;
+    // accessibility tracing state
+    int mAccessibilityTracingState = 0;
 
     AccessibilityPolicy mAccessibilityPolicy;
 
@@ -1029,13 +1035,50 @@
     }
 
     /**
-     * Gets accessibility tracing enabled state.
+     * Gets accessibility interaction connection tracing enabled state.
      *
      * @hide
      */
-    public boolean isAccessibilityTracingEnabled() {
+    public boolean isA11yInteractionConnectionTraceEnabled() {
         synchronized (mLock) {
-            return mIsAccessibilityTracingEnabled;
+            return ((mAccessibilityTracingState
+                    & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED) != 0);
+        }
+    }
+
+    /**
+     * Gets accessibility interaction connection callback tracing enabled state.
+     *
+     * @hide
+     */
+    public boolean isA11yInteractionConnectionCBTraceEnabled() {
+        synchronized (mLock) {
+            return ((mAccessibilityTracingState
+                    & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED) != 0);
+        }
+    }
+
+    /**
+     * Gets accessibility interaction client tracing enabled state.
+     *
+     * @hide
+     */
+    public boolean isA11yInteractionClientTraceEnabled() {
+        synchronized (mLock) {
+            return ((mAccessibilityTracingState
+                    & STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED) != 0);
+        }
+    }
+
+    /**
+     * Gets accessibility service tracing enabled state.
+     *
+     * @hide
+     */
+    public boolean isA11yServiceTraceEnabled() {
+        synchronized (mLock) {
+            return ((mAccessibilityTracingState
+                    & STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED) != 0);
         }
     }
 
@@ -1233,8 +1276,6 @@
                 (stateFlags & STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0;
         final boolean highTextContrastEnabled =
                 (stateFlags & STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED) != 0;
-        final boolean accessibilityTracingEnabled =
-                (stateFlags & STATE_FLAG_ACCESSIBILITY_TRACING_ENABLED) != 0;
 
         final boolean wasEnabled = isEnabled();
         final boolean wasTouchExplorationEnabled = mIsTouchExplorationEnabled;
@@ -1257,7 +1298,7 @@
             notifyHighTextContrastStateChanged();
         }
 
-        updateAccessibilityTracingState(accessibilityTracingEnabled);
+        updateAccessibilityTracingState(stateFlags);
     }
 
     /**
@@ -1715,11 +1756,11 @@
     }
 
     /**
-     * Update mIsAccessibilityTracingEnabled.
+     * Update mAccessibilityTracingState.
      */
-    private void updateAccessibilityTracingState(boolean enabled) {
+    private void updateAccessibilityTracingState(int stateFlag) {
         synchronized (mLock) {
-            mIsAccessibilityTracingEnabled = enabled;
+            mAccessibilityTracingState = stateFlag;
         }
     }
 
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index c3a4d32..f26abb2 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -20,8 +20,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcelable;
+import android.view.Display;
 import android.view.View;
 
 import java.util.ArrayList;
@@ -104,6 +106,7 @@
     @UnsupportedAppUsage
     long mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
     int mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+    int mSourceDisplayId = Display.INVALID_DISPLAY;
 
     CharSequence mClassName;
     CharSequence mContentDescription;
@@ -202,6 +205,27 @@
     }
 
     /**
+     * Sets the display id.
+     *
+     * @param displayId The displayId id.
+     *
+     * @hide
+     */
+    @TestApi
+    public void setDisplayId(int displayId) {
+        mSourceDisplayId = displayId;
+    }
+
+    /**
+     * Gets the id of the display from which the event comes from.
+     *
+     * @return The display id.
+     */
+    public int getDisplayId() {
+        return mSourceDisplayId;
+    }
+
+    /**
      * Sets the window id.
      *
      * @param windowId The window id.
@@ -886,6 +910,7 @@
         mText.addAll(record.mText);
         mSourceWindowId = record.mSourceWindowId;
         mSourceNodeId = record.mSourceNodeId;
+        mSourceDisplayId = record.mSourceDisplayId;
         mConnectionId = record.mConnectionId;
     }
 
@@ -914,6 +939,7 @@
         mText.clear();
         mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
         mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+        mSourceDisplayId = Display.INVALID_DISPLAY;
         mConnectionId = UNDEFINED;
     }
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4df8fd2..a169cb0 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -25,6 +25,7 @@
 import static android.view.autofill.Helper.toList;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -45,16 +46,21 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.AutofillService;
+import android.service.autofill.FillCallback;
 import android.service.autofill.FillEventHistory;
+import android.service.autofill.IFillCallback;
 import android.service.autofill.UserData;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -74,6 +80,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.TextView;
@@ -99,6 +106,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 import sun.misc.Cleaner;
 
@@ -167,6 +175,12 @@
  * shows an autofill save UI if the value of savable views have changed. If the user selects the
  * option to Save, the current value of the views is then sent to the autofill service.
  *
+ * <p>There is another choice for the application to provide it's datasets to the Autofill framework
+ * by setting an {@link AutofillRequestCallback} through
+ * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use
+ * its callback instead of the default {@link AutofillService}. See
+ * {@link AutofillRequestCallback} for more details.
+ *
  * <h3 id="additional-notes">Additional notes</h3>
  *
  * <p>It is safe to call <code>AutofillManager</code> methods from any thread.
@@ -292,6 +306,7 @@
     /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
     /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
     /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;
+    /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20;
 
     // NOTE: flag below is used by the session start receiver only, hence it can have values above
     /** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
@@ -592,6 +607,11 @@
     @GuardedBy("mLock")
     private boolean mEnabledForAugmentedAutofillOnly;
 
+    @GuardedBy("mLock")
+    @Nullable private AutofillRequestCallback mAutofillRequestCallback;
+    @GuardedBy("mLock")
+    @Nullable private Executor mRequestCallbackExecutor;
+
     /** @hide */
     public interface AutofillClient {
         /**
@@ -1836,6 +1856,32 @@
         return new AutofillId(parent.getAutofillViewId(), virtualId);
     }
 
+    /**
+     * Sets the client's suggestions callback for autofill.
+     *
+     * @see AutofillRequestCallback
+     *
+     * @param executor specifies the thread upon which the callbacks will be invoked.
+     * @param callback which handles autofill request to provide client's suggestions.
+     */
+    public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull AutofillRequestCallback callback) {
+        synchronized (mLock) {
+            mRequestCallbackExecutor = executor;
+            mAutofillRequestCallback = callback;
+        }
+    }
+
+    /**
+     * clears the client's suggestions callback for autofill.
+     */
+    public void clearAutofillRequestCallback() {
+        synchronized (mLock) {
+            mRequestCallbackExecutor = null;
+            mAutofillRequestCallback = null;
+        }
+    }
+
     @GuardedBy("mLock")
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
             @NonNull AutofillValue value, int flags) {
@@ -1896,6 +1942,13 @@
                 }
             }
 
+            if (mAutofillRequestCallback != null) {
+                if (sDebug) {
+                    Log.d(TAG, "startSession with the client suggestions provider");
+                }
+                flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS;
+            }
+
             mService.startSession(client.autofillClientGetActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, clientActivity,
@@ -2245,6 +2298,28 @@
         }
     }
 
+    private void onFillRequest(InlineSuggestionsRequest request,
+            CancellationSignal cancellationSignal, FillCallback callback) {
+        final AutofillRequestCallback autofillRequestCallback;
+        final Executor executor;
+        synchronized (mLock) {
+            autofillRequestCallback = mAutofillRequestCallback;
+            executor = mRequestCallbackExecutor;
+        }
+        if (autofillRequestCallback != null && executor != null) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                executor.execute(() ->
+                        autofillRequestCallback.onFillRequest(
+                                request, cancellationSignal, callback));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        } else {
+            callback.onSuccess(null);
+        }
+    }
+
     /** @hide */
     public static final int SET_STATE_FLAG_ENABLED = 0x01;
     /** @hide */
@@ -3624,6 +3699,23 @@
                 afm.post(() -> afm.requestShowSoftInput(id));
             }
         }
+
+        @Override
+        public void requestFillFromClient(int id, InlineSuggestionsRequest request,
+                IFillCallback callback) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                ICancellationSignal transport = CancellationSignal.createTransport();
+                try {
+                    callback.onCancellable(transport);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Error requesting a cancellation", e);
+                }
+
+                afm.onFillRequest(request, CancellationSignal.fromTransport(transport),
+                        new FillCallback(callback, id));
+            }
+        }
     }
 
     private static final class AugmentedAutofillManagerClient
diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java
new file mode 100644
index 0000000..e632a58
--- /dev/null
+++ b/core/java/android/view/autofill/AutofillRequestCallback.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.CancellationSignal;
+import android.service.autofill.FillCallback;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+/**
+ * <p>This class is used to provide some input suggestions to the Autofill framework.
+ *
+ * <P>When the user is requested to input something, Autofill will try to query input suggestions
+ * for the user choosing. If the application want to provide some internal input suggestions,
+ * implements this callback and register via
+ * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor,
+ * AutofillRequestCallback)}. Autofill will callback the
+ * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request
+ * input suggestions.
+ *
+ * <P>To make sure the callback to take effect, must register before the autofill session starts.
+ * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current
+ * session, and then the callback will be used at the next restarted session.
+ *
+ * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch
+ * {@link AutofillId}s from its view structure. Below is an example:
+ * <pre class="prettyprint">
+ * AutofillId usernameId = findViewById(R.id.username).getAutofillId();
+ * AutofillId passwordId = findViewById(R.id.password).getAutofillId();
+ * </pre>
+ * To learn more about creating a {@link android.service.autofill.FillResponse}, read
+ * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>.
+ *
+ * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond
+ * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill
+ * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback
+ * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the
+ * client would like to keep no suggestions for the field, respond with an empty
+ * {@link android.service.autofill.FillResponse} which has no dataset.
+ *
+ * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or
+ * the keyboard may choose to block your app from the inline strip.
+ */
+public interface AutofillRequestCallback {
+    /**
+     * Called by the Android system to decide if a screen can be autofilled by the callback.
+     *
+     * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if
+     *     currently inline suggestions are supported and can be displayed.
+     * @param cancellationSignal signal for observing cancellation requests. The system will use
+     *     this to notify you that the fill result is no longer needed and you should stop
+     *     handling this fill request in order to save resources.
+     * @param callback object used to notify the result of the request.
+     */
+    void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
+}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 1f833f6..64507aa 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -24,9 +24,11 @@
 import android.content.IntentSender;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.service.autofill.IFillCallback;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.KeyEvent;
 
 import com.android.internal.os.IResultReceiver;
@@ -140,4 +142,10 @@
     * Requests to show the soft input method if the focus is on the given id.
     */
    void requestShowSoftInput(in AutofillId id);
+
+    /**
+     * Requests to determine if a screen can be autofilled by the client app.
+     */
+    void requestFillFromClient(int id, in InlineSuggestionsRequest request,
+            in IFillCallback callback);
 }
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 1eb1a93..e1e1755 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -111,6 +111,22 @@
     private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
 
     /**
+     * Whether the IME supports inline suggestions from the default Autofill service that
+     * provides the input view.
+     *
+     * Note: The default value is {@code true}.
+     */
+    private boolean mServiceSupported;
+
+    /**
+     * Whether the IME supports inline suggestions from the application that provides the
+     * input view.
+     *
+     * Note: The default value is {@code true}.
+     */
+    private boolean mClientSupported;
+
+    /**
      * @hide
      * @see {@link #mHostInputToken}.
      */
@@ -204,6 +220,14 @@
         return Bundle.EMPTY;
     }
 
+    private static boolean defaultServiceSupported() {
+        return true;
+    }
+
+    private static boolean defaultClientSupported() {
+        return true;
+    }
+
     /** @hide */
     abstract static class BaseBuilder {
         abstract Builder setInlinePresentationSpecs(
@@ -216,15 +240,25 @@
         abstract Builder setHostDisplayId(int value);
     }
 
+    /** @hide */
+    public boolean isServiceSupported() {
+        return mServiceSupported;
+    }
+
+    /** @hide */
+    public boolean isClientSupported() {
+        return mClientSupported;
+    }
 
 
-    // Code below generated by codegen v1.0.23.
+
+    // Code below generated by codegen v1.0.22.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/./frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -240,7 +274,9 @@
             @NonNull Bundle extras,
             @Nullable IBinder hostInputToken,
             int hostDisplayId,
-            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec) {
+            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
+            boolean serviceSupported,
+            boolean clientSupported) {
         this.mMaxSuggestionCount = maxSuggestionCount;
         this.mInlinePresentationSpecs = inlinePresentationSpecs;
         com.android.internal.util.AnnotationValidations.validate(
@@ -257,6 +293,8 @@
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
         this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
+        this.mServiceSupported = serviceSupported;
+        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -340,7 +378,9 @@
     }
 
     /**
-     * Specifies the UI specification for the inline suggestion tooltip in the response.
+     * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
+     *
+     * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
      */
     @DataClass.Generated.Member
     public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
@@ -361,7 +401,9 @@
                 "extras = " + mExtras + ", " +
                 "hostInputToken = " + mHostInputToken + ", " +
                 "hostDisplayId = " + mHostDisplayId + ", " +
-                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec +
+                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
+                "serviceSupported = " + mServiceSupported + ", " +
+                "clientSupported = " + mClientSupported +
         " }";
     }
 
@@ -385,7 +427,9 @@
                 && extrasEquals(that.mExtras)
                 && java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
                 && mHostDisplayId == that.mHostDisplayId
-                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec);
+                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
+                && mServiceSupported == that.mServiceSupported
+                && mClientSupported == that.mClientSupported;
     }
 
     @Override
@@ -403,6 +447,8 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
         _hash = 31 * _hash + mHostDisplayId;
         _hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
+        _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
+        _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
         return _hash;
     }
 
@@ -413,6 +459,8 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         int flg = 0;
+        if (mServiceSupported) flg |= 0x100;
+        if (mClientSupported) flg |= 0x200;
         if (mHostInputToken != null) flg |= 0x20;
         if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
         dest.writeInt(flg);
@@ -438,6 +486,8 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         int flg = in.readInt();
+        boolean serviceSupported = (flg & 0x100) != 0;
+        boolean clientSupported = (flg & 0x200) != 0;
         int maxSuggestionCount = in.readInt();
         List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
         in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader());
@@ -464,6 +514,8 @@
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
         this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
+        this.mServiceSupported = serviceSupported;
+        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -497,6 +549,8 @@
         private @Nullable IBinder mHostInputToken;
         private int mHostDisplayId;
         private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
+        private boolean mServiceSupported;
+        private boolean mClientSupported;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -629,7 +683,9 @@
         }
 
         /**
-         * Specifies the UI specification for the inline suggestion tooltip in the response.
+         * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
+         *
+         * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
          */
         @DataClass.Generated.Member
         public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
@@ -639,10 +695,38 @@
             return this;
         }
 
+        /**
+         * Whether the IME supports inline suggestions from the default Autofill service that
+         * provides the input view.
+         *
+         * Note: The default value is {@code true}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setServiceSupported(boolean value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100;
+            mServiceSupported = value;
+            return this;
+        }
+
+        /**
+         * Whether the IME supports inline suggestions from the application that provides the
+         * input view.
+         *
+         * Note: The default value is {@code true}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setClientSupported(boolean value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x200;
+            mClientSupported = value;
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull InlineSuggestionsRequest build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x100; // Mark builder used
+            mBuilderFieldsSet |= 0x400; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -665,6 +749,12 @@
             if ((mBuilderFieldsSet & 0x80) == 0) {
                 mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
             }
+            if ((mBuilderFieldsSet & 0x100) == 0) {
+                mServiceSupported = defaultServiceSupported();
+            }
+            if ((mBuilderFieldsSet & 0x200) == 0) {
+                mClientSupported = defaultClientSupported();
+            }
             InlineSuggestionsRequest o = new InlineSuggestionsRequest(
                     mMaxSuggestionCount,
                     mInlinePresentationSpecs,
@@ -673,12 +763,14 @@
                     mExtras,
                     mHostInputToken,
                     mHostDisplayId,
-                    mInlineTooltipPresentationSpec);
+                    mInlineTooltipPresentationSpec,
+                    mServiceSupported,
+                    mClientSupported);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x100) != 0) {
+            if ((mBuilderFieldsSet & 0x400) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -686,10 +778,10 @@
     }
 
     @DataClass.Generated(
-            time = 1621415989607L,
-            codegenVersion = "1.0.23",
+            time = 1615798784918L,
+            codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
-            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate  boolean mServiceSupported\nprivate  boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static  boolean defaultServiceSupported()\nprivate static  boolean defaultClientSupported()\npublic  boolean isServiceSupported()\npublic  boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index be49fc4..91412d7 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -178,12 +178,23 @@
      */
     static void reserveAddressSpaceInZygote() {
         System.loadLibrary("webviewchromium_loader");
-        boolean is64Bit = VMRuntime.getRuntime().is64Bit();
-        // On 64-bit address space is really cheap and we can reserve 1GB which is plenty.
-        // On 32-bit it's fairly scarce and we should keep it to a realistic number that
-        // permits some future growth but doesn't hog space: we use 130MB which is roughly
-        // what was calculated on older OS versions in practice.
-        long addressSpaceToReserve = is64Bit ? 1 * 1024 * 1024 * 1024 : 130 * 1024 * 1024;
+        long addressSpaceToReserve;
+        if (VMRuntime.getRuntime().is64Bit()) {
+            // On 64-bit address space is really cheap and we can reserve 1GB which is plenty.
+            addressSpaceToReserve = 1 * 1024 * 1024 * 1024;
+        } else if (VMRuntime.getRuntime().vmInstructionSet().equals("arm")) {
+            // On 32-bit the address space is fairly scarce, hence we should keep it to a realistic
+            // number that permits some future growth but doesn't hog space. For ARM we use 130MB
+            // which is roughly what was calculated on older OS versions. The size has been
+            // growing gradually, but a few efforts have offset it back to the size close to the
+            // original.
+            addressSpaceToReserve = 130 * 1024 * 1024;
+        } else {
+            // The number below was obtained for a binary used for x86 emulators, allowing some
+            // natural growth.
+            addressSpaceToReserve = 190 * 1024 * 1024;
+        }
+
         sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
 
         if (sAddressSpaceReserved) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index f9f823b..26579c5 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -480,6 +480,17 @@
             return false;
         }
 
+        /**
+         * @see View#onApplyWindowInsets(WindowInsets).
+         *
+         * <p>This is the entry point for the WebView implementation to override. It returns
+         * {@code null} when the WebView implementation hasn't implemented the WindowInsets support
+         * on S yet. In this case, the {@link View#onApplyWindowInsets()} super method will be
+         * called instead.
+         *
+         * @param insets Insets to apply
+         * @return The supplied insets with any applied insets consumed.
+         */
         @SuppressWarnings("unused")
         @Nullable
         default WindowInsets onApplyWindowInsets(@Nullable WindowInsets insets) {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index d8f7f4c..f3dfda5 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -412,24 +412,29 @@
     }
 
     void refreshChildren() {
-        if (mAdapter == null) return;
+        final int adapterCount = mAdapter == null ? 0 : getCount();
         for (int i = mCurrentWindowStart; i <= mCurrentWindowEnd; i++) {
             int index = modulo(i, getWindowSize());
 
-            int adapterCount = getCount();
-            // get the fresh child from the adapter
-            final View updatedChild = mAdapter.getView(modulo(i, adapterCount), null, this);
+            final View updatedChild;
+            if (i < adapterCount) {
+                // get the fresh child from the adapter
+                updatedChild = mAdapter.getView(modulo(i, adapterCount), null, this);
 
-            if (updatedChild.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-                updatedChild.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+                if (updatedChild.getImportantForAccessibility()
+                        == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                    updatedChild.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+                }
+            } else {
+                updatedChild = null;
             }
 
             if (mViewsMap.containsKey(index)) {
                 final FrameLayout fl = (FrameLayout) mViewsMap.get(index).view;
-                // add the new child to the frame, if it exists
+                // flush out the old child
+                fl.removeAllViewsInLayout();
                 if (updatedChild != null) {
-                    // flush out the old child
-                    fl.removeAllViewsInLayout();
+                    // add the new child to the frame, if it exists
                     fl.addView(updatedChild);
                 }
             }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 8aa557b..f292c61 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -136,6 +136,7 @@
 
     private int[] mState = null;
     private boolean mMergeState = false;
+    private boolean mHasLevelSet = false;
     private int mLevel = 0;
     @UnsupportedAppUsage
     private int mDrawableWidth;
@@ -798,6 +799,7 @@
     @android.view.RemotableViewMethod
     public void setImageLevel(int level) {
         mLevel = level;
+        mHasLevelSet = true;
         if (mDrawable != null) {
             mDrawable.setLevel(level);
             resizeFromDrawable();
@@ -1069,7 +1071,9 @@
                         : isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
                 d.setVisible(visible, true);
             }
-            d.setLevel(mLevel);
+            if (mHasLevelSet) {
+                d.setLevel(mLevel);
+            }
             mDrawableWidth = d.getIntrinsicWidth();
             mDrawableHeight = d.getIntrinsicHeight();
             applyImageTint();
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 1b76ebf..356d059 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -245,8 +245,6 @@
 
     private boolean mAggregatedIsVisible;
 
-    private CharSequence mCustomStateDescription = null;
-
     private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
 
     private ObjectAnimator mLastProgressAnimator;
@@ -685,6 +683,9 @@
                 swapCurrentDrawable(mProgressDrawable);
                 stopAnimation();
             }
+
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
         }
     }
 
@@ -1622,18 +1623,21 @@
     @Override
     @RemotableViewMethod
     public void setStateDescription(@Nullable CharSequence stateDescription) {
-        mCustomStateDescription = stateDescription;
-        if (stateDescription == null) {
-            super.setStateDescription(formatStateDescription(mProgress));
-        } else {
-            super.setStateDescription(stateDescription);
-        }
+        // Assume the previous custom state description is different from default state description.
+        // Otherwise when the argument is null to restore the default state description, we will
+        // send out a state description changed event even though the state description presented to
+        // the user doesn't change. Since mStateDescription in View is private, we can't prevent
+        // this event from sending out.
+        super.setStateDescription(stateDescription);
     }
 
     void onProgressRefresh(float scale, boolean fromUser, int progress) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()
-                && mCustomStateDescription == null) {
-            super.setStateDescription(formatStateDescription(mProgress));
+                && getStateDescription() == null && !isIndeterminate()) {
+            AccessibilityEvent event = AccessibilityEvent.obtain();
+            event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+            event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION);
+            sendAccessibilityEventUnchecked(event);
         }
     }
 
@@ -2356,7 +2360,15 @@
                     AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
                     getProgress());
             info.setRangeInfo(rangeInfo);
-            info.setStateDescription(formatStateDescription(mProgress));
+        }
+
+        // Only set the default state description when custom state descripton is null.
+        if (getStateDescription() == null) {
+            if (isIndeterminate()) {
+                info.setStateDescription(getResources().getString(R.string.in_progress));
+            } else {
+                info.setStateDescription(formatStateDescription(mProgress));
+            }
         }
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 37374ef..dc6b091 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -200,6 +200,7 @@
 import android.view.translation.ViewTranslationRequest;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -6318,6 +6319,11 @@
             text = TextUtils.stringOrSpannedString(text);
         }
 
+        @AccessibilityUtils.A11yTextChangeType int a11yTextChangeType = AccessibilityUtils.NONE;
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            a11yTextChangeType = AccessibilityUtils.textOrSpanChanged(text, mText);
+        }
+
         if (mAutoLinkMask != 0) {
             Spannable s2;
 
@@ -6337,6 +6343,9 @@
                  * setText() again to try to upgrade the buffer type.
                  */
                 setTextInternal(text);
+                if (a11yTextChangeType == AccessibilityUtils.NONE) {
+                    a11yTextChangeType = AccessibilityUtils.PARCELABLE_SPAN;
+                }
 
                 // Do not change the movement method for text that support text selection as it
                 // would prevent an arbitrary cursor displacement.
@@ -6401,7 +6410,13 @@
         sendOnTextChanged(text, 0, oldlen, textLength);
         onTextChanged(text, 0, oldlen, textLength);
 
-        notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
+        if (a11yTextChangeType == AccessibilityUtils.TEXT) {
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
+        } else if (a11yTextChangeType == AccessibilityUtils.PARCELABLE_SPAN) {
+            notifyViewAccessibilityStateChangedIfNeeded(
+                    AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+        }
 
         if (needEditableForNotification) {
             sendAfterTextChanged((Editable) text);
diff --git a/core/java/android/window/ConfigurationHelper.java b/core/java/android/window/ConfigurationHelper.java
new file mode 100644
index 0000000..9a07975
--- /dev/null
+++ b/core/java/android/window/ConfigurationHelper.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 android.window;
+
+import static android.view.Display.INVALID_DISPLAY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ResourcesManager;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.Display;
+import android.view.WindowManager;
+
+/**
+ * A helper class to maintain {@link android.content.res.Configuration} related methods used both
+ * in {@link android.app.Activity} and {@link WindowContext}.
+ *
+ * @hide
+ */
+public class ConfigurationHelper {
+    private ConfigurationHelper() {}
+
+    /** Ask text layout engine to free its caches if there is a locale change. */
+    public static void freeTextLayoutCachesIfNeeded(int configDiff) {
+        if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
+            Canvas.freeTextLayoutCaches();
+        }
+    }
+
+    /**
+     * A helper method to filter out {@link ActivityInfo#CONFIG_SCREEN_SIZE} if the
+     * {@link Configuration#diffPublicOnly(Configuration) diff} of two {@link Configuration}
+     * doesn't cross the boundary.
+     *
+     * @see SizeConfigurationBuckets#filterDiff(int, Configuration, Configuration,
+     * SizeConfigurationBuckets)
+     */
+    public static int diffPublicWithSizeBuckets(@Nullable Configuration currentConfig,
+            @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) {
+        // If current configuration is null, it is definitely different from updated Configuration.
+        if (currentConfig == null) {
+            return 0xffffffff;
+        }
+        int publicDiff = currentConfig.diffPublicOnly(newConfig);
+        return SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig, newConfig, buckets);
+    }
+
+    /**
+     * Returns {@code true} if the {@link android.content.res.Resources} associated with
+     * a {@code token} needs to be updated.
+     *
+     * @param token A {@link Context#getActivityToken() activity token} or
+     * {@link Context#getWindowContextToken() window context token}
+     * @param config The original {@link Configuration}
+     * @param newConfig The updated Configuration
+     * @param displayChanged a flag to indicate there's a display change
+     * @param configChanged a flag to indicate there's a Configuration change.
+     *
+     * @see ResourcesManager#updateResourcesForActivity(IBinder, Configuration, int)
+     */
+    public static boolean shouldUpdateResources(IBinder token, @Nullable Configuration config,
+            @NonNull Configuration newConfig, @NonNull Configuration overrideConfig,
+            boolean displayChanged, @Nullable Boolean configChanged) {
+        // The configuration has not yet been initialized. We should update it.
+        if (config == null) {
+            return true;
+        }
+        // If the token associated context is moved to another display, we should update the
+        // ResourcesKey.
+        if (displayChanged) {
+            return true;
+        }
+        // If the new config is the same as the config this Activity is already running with and
+        // the override config also didn't change, then don't update the Resources
+        if (!ResourcesManager.getInstance().isSameResourcesOverrideConfig(token, overrideConfig)) {
+            return true;
+        }
+        // If there's a update on WindowConfiguration#mBounds or maxBounds, we should update the
+        // Resources to make WindowMetrics API report the updated result.
+        if (shouldUpdateWindowMetricsBounds(config, newConfig)) {
+            return true;
+        }
+        return configChanged == null ? config.diff(newConfig) != 0 : configChanged;
+    }
+
+    /**
+     * Returns {@code true} if {@code displayId} is different from {@code newDisplayId}.
+     * Note that {@link Display#INVALID_DISPLAY} means no difference.
+     */
+    public static boolean isDifferentDisplay(int displayId, int newDisplayId) {
+        return newDisplayId != INVALID_DISPLAY && displayId != newDisplayId;
+    }
+
+    // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl
+    // constructions.
+    /**
+     * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs
+     * should be updated.
+     *
+     * @see WindowManager#getCurrentWindowMetrics()
+     * @see WindowManager#getMaximumWindowMetrics()
+     */
+    private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
+            @NonNull Configuration newConfig) {
+        final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
+        final Rect newBounds = newConfig.windowConfiguration.getBounds();
+
+        final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds();
+        final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds();
+
+        return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds);
+    }
+}
diff --git a/core/java/android/window/DisplayAreaInfo.java b/core/java/android/window/DisplayAreaInfo.java
index 358467f..1a7aab6 100644
--- a/core/java/android/window/DisplayAreaInfo.java
+++ b/core/java/android/window/DisplayAreaInfo.java
@@ -16,6 +16,8 @@
 
 package android.window;
 
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
+
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.content.res.Configuration;
@@ -43,8 +45,17 @@
      */
     public final int displayId;
 
+    /**
+     * The feature id of this display area.
+     */
     public final int featureId;
 
+    /**
+     * The feature id of the root display area this display area is associated with.
+     * @hide
+     */
+    public int rootDisplayAreaId = FEATURE_UNDEFINED;
+
     public DisplayAreaInfo(@NonNull WindowContainerToken token, int displayId, int featureId) {
         this.token = token;
         this.displayId = displayId;
@@ -56,6 +67,7 @@
         configuration.readFromParcel(in);
         displayId = in.readInt();
         featureId = in.readInt();
+        rootDisplayAreaId = in.readInt();
     }
 
     @Override
@@ -64,6 +76,7 @@
         configuration.writeToParcel(dest, flags);
         dest.writeInt(displayId);
         dest.writeInt(featureId);
+        dest.writeInt(rootDisplayAreaId);
     }
 
     @NonNull
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 8784399..e674655 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -34,6 +34,15 @@
 public class DisplayAreaOrganizer extends WindowOrganizer {
 
     /**
+     * Key to specify the {@link com.android.server.wm.RootDisplayArea} to attach a window to.
+     * It will be used by the function passed in from
+     * {@link com.android.server.wm.DisplayAreaPolicyBuilder#setSelectRootForWindowFunc(BiFunction)}
+     * to find the Root DA to attach the window.
+     * @hide
+     */
+    public static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id";
+
+    /**
      * The value in display area indicating that no value has been set.
      */
     public static final int FEATURE_UNDEFINED = -1;
diff --git a/core/java/android/window/IRemoteTransitionFinishedCallback.aidl b/core/java/android/window/IRemoteTransitionFinishedCallback.aidl
index 02aa1a9..7864c24 100644
--- a/core/java/android/window/IRemoteTransitionFinishedCallback.aidl
+++ b/core/java/android/window/IRemoteTransitionFinishedCallback.aidl
@@ -16,14 +16,18 @@
 
 package android.window;
 
+import android.view.SurfaceControl;
 import android.window.WindowContainerTransaction;
 
 /**
  * Interface to be invoked by the controlling process when a remote transition has finished.
  *
  * @see IRemoteTransition
+ * @param wct An optional WindowContainerTransaction to apply before the transition finished.
+ * @param sct An optional Surface Transaction that is added to the end of the finish/cleanup
+ *            transaction. This is applied by shell.Transitions (before submitting the wct).
  * {@hide}
  */
 interface IRemoteTransitionFinishedCallback {
-    void onTransitionFinished(in WindowContainerTransaction wct);
+    void onTransitionFinished(in WindowContainerTransaction wct, in SurfaceControl.Transaction sct);
 }
diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl
new file mode 100644
index 0000000..0bfc254
--- /dev/null
+++ b/core/java/android/window/ITaskFragmentOrganizer.aidl
@@ -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 android.window;
+
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.window.TaskFragmentAppearedInfo;
+import android.window.TaskFragmentInfo;
+
+/** @hide */
+oneway interface ITaskFragmentOrganizer {
+    void onTaskFragmentAppeared(in TaskFragmentAppearedInfo taskFragmentAppearedInfo);
+    void onTaskFragmentInfoChanged(in TaskFragmentInfo taskFragmentInfo);
+    void onTaskFragmentVanished(in TaskFragmentInfo taskFragmentInfo);
+
+    /**
+     * Called when the parent leaf Task of organized TaskFragments is changed.
+     * When the leaf Task is changed, the organizer may want to update the TaskFragments in one
+     * transaction.
+     *
+     * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
+     * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
+     * bounds.
+     */
+    void onTaskFragmentParentInfoChanged(in IBinder fragmentToken, in Configuration parentConfig);
+}
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
new file mode 100644
index 0000000..0ca8a86
--- /dev/null
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -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 android.window;
+
+import android.window.ITaskFragmentOrganizer;
+
+/** @hide */
+interface ITaskFragmentOrganizerController {
+
+    /**
+     * Registers a TaskFragmentOrganizer to manage TaskFragments.
+     */
+    void registerOrganizer(in ITaskFragmentOrganizer organizer);
+
+    /**
+     * Unregisters a previously registered TaskFragmentOrganizer.
+     */
+    void unregisterOrganizer(in ITaskFragmentOrganizer organizer);
+}
diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl
index 1223d72..39cdf5a 100644
--- a/core/java/android/window/IWindowOrganizerController.aidl
+++ b/core/java/android/window/IWindowOrganizerController.aidl
@@ -20,6 +20,7 @@
 
 import android.os.IBinder;
 import android.window.IDisplayAreaOrganizerController;
+import android.window.ITaskFragmentOrganizerController;
 import android.window.ITaskOrganizerController;
 import android.window.ITransitionPlayer;
 import android.window.IWindowContainerTransactionCallback;
@@ -77,6 +78,9 @@
     /** @return An interface enabling the management of display area organizers. */
     IDisplayAreaOrganizerController getDisplayAreaOrganizerController();
 
+    /** @return An interface enabling the management of task fragment organizers. */
+    ITaskFragmentOrganizerController getTaskFragmentOrganizerController();
+
     /**
      * Registers a transition player with Core. There is only one of these at a time and calling
      * this will replace the existing one if set.
diff --git a/core/java/android/window/TaskFragmentAppearedInfo.aidl b/core/java/android/window/TaskFragmentAppearedInfo.aidl
new file mode 100644
index 0000000..3729c09
--- /dev/null
+++ b/core/java/android/window/TaskFragmentAppearedInfo.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+/**
+ * Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer.
+ * @hide
+ */
+parcelable TaskFragmentAppearedInfo;
diff --git a/core/java/android/window/TaskFragmentAppearedInfo.java b/core/java/android/window/TaskFragmentAppearedInfo.java
new file mode 100644
index 0000000..234b30c
--- /dev/null
+++ b/core/java/android/window/TaskFragmentAppearedInfo.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 android.window;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.SurfaceControl;
+
+/**
+ * Data object for the TaskFragment info provided when a TaskFragment is presented to an organizer.
+ * @hide
+ */
+public final class TaskFragmentAppearedInfo implements Parcelable {
+
+    @NonNull
+    private final TaskFragmentInfo mTaskFragmentInfo;
+
+    @NonNull
+    private final SurfaceControl mLeash;
+
+    public TaskFragmentAppearedInfo(
+            @NonNull TaskFragmentInfo taskFragmentInfo, @NonNull SurfaceControl leash) {
+        mTaskFragmentInfo = taskFragmentInfo;
+        mLeash = leash;
+    }
+
+    public TaskFragmentInfo getTaskFragmentInfo() {
+        return mTaskFragmentInfo;
+    }
+
+    public SurfaceControl getLeash() {
+        return mLeash;
+    }
+
+    private TaskFragmentAppearedInfo(Parcel in) {
+        mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR);
+        mLeash = in.readTypedObject(SurfaceControl.CREATOR);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mTaskFragmentInfo, flags);
+        dest.writeTypedObject(mLeash, flags);
+    }
+
+    @NonNull
+    public static final Creator<TaskFragmentAppearedInfo> CREATOR =
+            new Creator<TaskFragmentAppearedInfo>() {
+                @Override
+                public TaskFragmentAppearedInfo createFromParcel(Parcel in) {
+                    return new TaskFragmentAppearedInfo(in);
+                }
+
+                @Override
+                public TaskFragmentAppearedInfo[] newArray(int size) {
+                    return new TaskFragmentAppearedInfo[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "TaskFragmentAppearedInfo{"
+                + " taskFragmentInfo=" + mTaskFragmentInfo
+                + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/window/TaskFragmentCreationParams.aidl b/core/java/android/window/TaskFragmentCreationParams.aidl
new file mode 100644
index 0000000..fde5089
--- /dev/null
+++ b/core/java/android/window/TaskFragmentCreationParams.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+/**
+ * Data object for options to create TaskFragment with.
+ * @hide
+ */
+parcelable TaskFragmentCreationParams;
diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java
new file mode 100644
index 0000000..e4d6a6c
--- /dev/null
+++ b/core/java/android/window/TaskFragmentCreationParams.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.WindowingMode;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Data object for options to create TaskFragment with.
+ * @hide
+ */
+public final class TaskFragmentCreationParams implements Parcelable {
+
+    /** The organizer that will organize this TaskFragment. */
+    @NonNull
+    private final ITaskFragmentOrganizer mOrganizer;
+
+    /**
+     * Unique token assigned from the client organizer to identify the {@link TaskFragmentInfo} when
+     * a new TaskFragment is created with this option.
+     */
+    @NonNull
+    private final IBinder mFragmentToken;
+
+    /**
+     * Activity token used to identify the leaf Task to create the TaskFragment in. It has to belong
+     * to the same app as the root Activity of the target Task.
+     */
+    @NonNull
+    private final IBinder mOwnerToken;
+
+    /** The initial bounds of the TaskFragment. Fills parent if empty. */
+    @NonNull
+    private final Rect mInitialBounds = new Rect();
+
+    /** The initial windowing mode of the TaskFragment. Inherits from parent if not set. */
+    @WindowingMode
+    private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+
+    private TaskFragmentCreationParams(
+            @NonNull ITaskFragmentOrganizer organizer, @NonNull IBinder fragmentToken,
+            @NonNull IBinder ownerToken) {
+        mOrganizer = organizer;
+        mFragmentToken = fragmentToken;
+        mOwnerToken = ownerToken;
+    }
+
+    public ITaskFragmentOrganizer getOrganizer() {
+        return mOrganizer;
+    }
+
+    public IBinder getFragmentToken() {
+        return mFragmentToken;
+    }
+
+    public IBinder getOwnerToken() {
+        return mOwnerToken;
+    }
+
+    public Rect getInitialBounds() {
+        return mInitialBounds;
+    }
+
+    @WindowingMode
+    public int getWindowingMode() {
+        return mWindowingMode;
+    }
+
+    private TaskFragmentCreationParams(Parcel in) {
+        mOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
+        mFragmentToken = in.readStrongBinder();
+        mOwnerToken = in.readStrongBinder();
+        mInitialBounds.readFromParcel(in);
+        mWindowingMode = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeStrongInterface(mOrganizer);
+        dest.writeStrongBinder(mFragmentToken);
+        dest.writeStrongBinder(mOwnerToken);
+        mInitialBounds.writeToParcel(dest, flags);
+        dest.writeInt(mWindowingMode);
+    }
+
+    @NonNull
+    public static final Creator<TaskFragmentCreationParams> CREATOR =
+            new Creator<TaskFragmentCreationParams>() {
+                @Override
+                public TaskFragmentCreationParams createFromParcel(Parcel in) {
+                    return new TaskFragmentCreationParams(in);
+                }
+
+                @Override
+                public TaskFragmentCreationParams[] newArray(int size) {
+                    return new TaskFragmentCreationParams[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "TaskFragmentCreationParams{"
+                + " organizer=" + mOrganizer
+                + " fragmentToken=" + mFragmentToken
+                + " ownerToken=" + mOwnerToken
+                + " initialBounds=" + mInitialBounds
+                + " windowingMode=" + mWindowingMode
+                + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Builder to construct the options to create TaskFragment with. */
+    public static class Builder {
+
+        @NonNull
+        private final ITaskFragmentOrganizer mOrganizer;
+
+        @NonNull
+        private final IBinder mFragmentToken;
+
+        @NonNull
+        private final IBinder mOwnerToken;
+
+        @NonNull
+        private final Rect mInitialBounds = new Rect();
+
+        @WindowingMode
+        private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+
+        public Builder(@NonNull ITaskFragmentOrganizer organizer, @NonNull IBinder fragmentToken,
+                @NonNull IBinder ownerToken) {
+            mOrganizer = organizer;
+            mFragmentToken = fragmentToken;
+            mOwnerToken = ownerToken;
+        }
+
+        /** Sets the initial bounds for the TaskFragment. */
+        public Builder setInitialBounds(@NonNull Rect bounds) {
+            mInitialBounds.set(bounds);
+            return this;
+        }
+
+        /** Sets the initial windowing mode for the TaskFragment. */
+        public Builder setWindowingMode(@WindowingMode int windowingMode) {
+            mWindowingMode = windowingMode;
+            return this;
+        }
+
+        /** Constructs the options to create TaskFragment with. */
+        public TaskFragmentCreationParams build() {
+            final TaskFragmentCreationParams result = new TaskFragmentCreationParams(
+                    mOrganizer, mFragmentToken, mOwnerToken);
+            result.mInitialBounds.set(mInitialBounds);
+            result.mWindowingMode = mWindowingMode;
+            return result;
+        }
+    }
+}
diff --git a/core/java/android/window/TaskFragmentInfo.aidl b/core/java/android/window/TaskFragmentInfo.aidl
new file mode 100644
index 0000000..461a736
--- /dev/null
+++ b/core/java/android/window/TaskFragmentInfo.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+/**
+ * Stores information about a particular TaskFragment.
+ * @hide
+ */
+parcelable TaskFragmentInfo;
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
new file mode 100644
index 0000000..e032153
--- /dev/null
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static android.app.WindowConfiguration.WindowingMode;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Stores information about a particular TaskFragment.
+ * @hide
+ */
+public final class TaskFragmentInfo implements Parcelable {
+
+    /**
+     * Client assigned unique token in {@link TaskFragmentCreationParams#fragmentToken} to create
+     * this TaskFragment with.
+     */
+    @NonNull
+    private final IBinder mFragmentToken;
+
+    /**
+     * The component name of the initial root activity of this TaskFragment, which will be used
+     * to configure the relationships for TaskFragments.
+     */
+    @NonNull
+    private final ComponentName mInitialComponentName;
+
+    @NonNull
+    private final WindowContainerToken mToken;
+
+    @NonNull
+    private final Configuration mConfiguration = new Configuration();
+
+    /** Whether the TaskFragment contains any child Activity. */
+    private final boolean mIsEmpty;
+
+    /** Whether this TaskFragment is visible on the window hierarchy. */
+    private final boolean mIsVisible;
+
+    public TaskFragmentInfo(
+            @NonNull IBinder fragmentToken, @NonNull ComponentName initialComponentName,
+            @NonNull WindowContainerToken token, @NonNull Configuration configuration,
+            boolean isEmpty, boolean isVisible) {
+        if (fragmentToken == null || initialComponentName == null) {
+            throw new IllegalArgumentException("Invalid TaskFragmentInfo.");
+        }
+        mFragmentToken = fragmentToken;
+        mInitialComponentName = initialComponentName;
+        mToken = token;
+        mConfiguration.setTo(configuration);
+        mIsEmpty = isEmpty;
+        mIsVisible = isVisible;
+    }
+
+    public IBinder getFragmentToken() {
+        return mFragmentToken;
+    }
+
+    public ComponentName getInitialComponentName() {
+        return mInitialComponentName;
+    }
+
+    public WindowContainerToken getToken() {
+        return mToken;
+    }
+
+    public Configuration getConfiguration() {
+        return mConfiguration;
+    }
+
+    public boolean isEmpty() {
+        return mIsEmpty;
+    }
+
+    public boolean isVisible() {
+        return mIsVisible;
+    }
+
+    @WindowingMode
+    public int getWindowingMode() {
+        return mConfiguration.windowConfiguration.getWindowingMode();
+    }
+
+    /**
+     * Returns {@code true} if the parameters that are important for task fragment organizers are
+     * equal between this {@link TaskFragmentInfo} and {@param that}.
+     */
+    public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentInfo that) {
+        if (that == null) {
+            return false;
+        }
+
+        return mFragmentToken.equals(that.mFragmentToken)
+                && mInitialComponentName.equals(that.mInitialComponentName)
+                && mToken.equals(that.mToken)
+                && mIsEmpty == that.mIsEmpty
+                && mIsVisible == that.mIsVisible
+                && getWindowingMode() == that.getWindowingMode();
+    }
+
+    private TaskFragmentInfo(Parcel in) {
+        mFragmentToken = in.readStrongBinder();
+        mInitialComponentName = in.readTypedObject(ComponentName.CREATOR);
+        mToken = in.readTypedObject(WindowContainerToken.CREATOR);
+        mConfiguration.readFromParcel(in);
+        mIsEmpty = in.readBoolean();
+        mIsVisible = in.readBoolean();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeStrongBinder(mFragmentToken);
+        dest.writeTypedObject(mInitialComponentName, flags);
+        dest.writeTypedObject(mToken, flags);
+        mConfiguration.writeToParcel(dest, flags);
+        dest.writeBoolean(mIsEmpty);
+        dest.writeBoolean(mIsVisible);
+    }
+
+    @NonNull
+    public static final Creator<TaskFragmentInfo> CREATOR =
+            new Creator<TaskFragmentInfo>() {
+                @Override
+                public TaskFragmentInfo createFromParcel(Parcel in) {
+                    return new TaskFragmentInfo(in);
+                }
+
+                @Override
+                public TaskFragmentInfo[] newArray(int size) {
+                    return new TaskFragmentInfo[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "TaskFragmentInfo{"
+                + " fragmentToken=" + mFragmentToken
+                + " initialComponentName=" + mInitialComponentName
+                + " token=" + mToken
+                + " isEmpty=" + mIsEmpty
+                + " isVisible=" + mIsVisible
+                + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
new file mode 100644
index 0000000..51722cc
--- /dev/null
+++ b/core/java/android/window/TaskFragmentOrganizer.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.window;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.content.res.Configuration;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Interface for WindowManager to delegate control of {@link com.android.server.wm.TaskFragment}.
+ * @hide
+ */
+public class TaskFragmentOrganizer extends WindowOrganizer {
+
+    /**
+     * Callbacks from WM Core are posted on this executor.
+     */
+    private final Executor mExecutor;
+
+    public TaskFragmentOrganizer(@NonNull Executor executor) {
+        mExecutor = executor;
+    }
+
+    /**
+     * Gets the executor to run callbacks on.
+     */
+    @NonNull
+    public Executor getExecutor() {
+        return mExecutor;
+    }
+
+    /**
+     * Registers a TaskFragmentOrganizer to manage TaskFragments.
+     */
+    @CallSuper
+    public void registerOrganizer() {
+        try {
+            getController().registerOrganizer(mInterface);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregisters a previously registered TaskFragmentOrganizer.
+     */
+    @CallSuper
+    public void unregisterOrganizer() {
+        try {
+            getController().unregisterOrganizer(mInterface);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Called when a TaskFragment is created and organized by this organizer. */
+    public void onTaskFragmentAppeared(
+            @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {}
+
+    /** Called when the status of an organized TaskFragment is changed. */
+    public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {}
+
+    /** Called when an organized TaskFragment is removed. */
+    public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {}
+
+    /**
+     * Called when the parent leaf Task of organized TaskFragments is changed.
+     * When the leaf Task is changed, the organizer may want to update the TaskFragments in one
+     * transaction.
+     *
+     * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
+     * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
+     * bounds.
+     */
+    public void onTaskFragmentParentInfoChanged(
+            @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
+
+    private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
+        @Override
+        public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) {
+            mExecutor.execute(
+                    () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo));
+        }
+
+        @Override
+        public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
+            mExecutor.execute(
+                    () -> TaskFragmentOrganizer.this.onTaskFragmentInfoChanged(taskFragmentInfo));
+        }
+
+        @Override
+        public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
+            mExecutor.execute(
+                    () -> TaskFragmentOrganizer.this.onTaskFragmentVanished(taskFragmentInfo));
+        }
+
+        @Override
+        public void onTaskFragmentParentInfoChanged(
+                @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
+            mExecutor.execute(
+                    () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged(
+                            fragmentToken, parentConfig));
+        }
+    };
+
+    private ITaskFragmentOrganizerController getController() {
+        try {
+            return getWindowOrganizerController().getTaskFragmentOrganizerController();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 141f47b..6351b03 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
@@ -33,6 +34,18 @@
  */
 public final class TransitionFilter implements Parcelable {
 
+    /** The associated requirement doesn't care about the z-order. */
+    public static final int CONTAINER_ORDER_ANY = 0;
+    /** The associated requirement only matches the top-most (z-order) container. */
+    public static final int CONTAINER_ORDER_TOP = 1;
+
+    /** @hide */
+    @IntDef(prefix = { "CONTAINER_ORDER_" }, value = {
+            CONTAINER_ORDER_ANY,
+            CONTAINER_ORDER_TOP,
+    })
+    public @interface ContainerOrder {}
+
     /**
      * When non-null: this is a list of transition types that this filter applies to. This filter
      * will fail for transitions that aren't one of these types.
@@ -126,6 +139,7 @@
     public static final class Requirement implements Parcelable {
         public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
         public int[] mModes = null;
+        public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY;
 
         public Requirement() {
         }
@@ -133,6 +147,7 @@
         private Requirement(Parcel in) {
             mActivityType = in.readInt();
             mModes = in.createIntArray();
+            mOrder = in.readInt();
         }
 
         /** Go through changes and find if at-least one change matches this filter */
@@ -143,6 +158,9 @@
                     // Only look at independent animating windows.
                     continue;
                 }
+                if (mOrder == CONTAINER_ORDER_TOP && i > 0) {
+                    continue;
+                }
                 if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
                     if (change.getTaskInfo() == null
                             || change.getTaskInfo().getActivityType() != mActivityType) {
@@ -166,7 +184,7 @@
 
         /** Check if the request matches this filter. It may generate false positives */
         boolean matches(@NonNull TransitionRequestInfo request) {
-            // Can't check modes since the transition hasn't been built at this point.
+            // Can't check modes/order since the transition hasn't been built at this point.
             if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true;
             return request.getTriggerTask() != null
                     && request.getTriggerTask().getActivityType() == mActivityType;
@@ -177,6 +195,7 @@
         public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeInt(mActivityType);
             dest.writeIntArray(mModes);
+            dest.writeInt(mOrder);
         }
 
         @NonNull
@@ -209,7 +228,17 @@
                     out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i]));
                 }
             }
-            return out.append("]}").toString();
+            out.append("]").toString();
+            out.append(" order=" + containerOrderToString(mOrder));
+            return out.toString();
         }
     }
+
+    private static String containerOrderToString(int order) {
+        switch (order) {
+            case CONTAINER_ORDER_ANY: return "ANY";
+            case CONTAINER_ORDER_TOP: return "TOP";
+        }
+        return "UNKNOWN(" + order + ")";
+    }
 }
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 23b8ee4..6430394 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -16,6 +16,12 @@
 
 package android.window;
 
+import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
+import static android.app.ActivityOptions.ANIM_CUSTOM;
+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.ROTATION_UNDEFINED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -31,6 +37,7 @@
 import android.app.ActivityManager;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.Surface;
@@ -102,6 +109,8 @@
     private SurfaceControl mRootLeash;
     private final Point mRootOffset = new Point();
 
+    private AnimationOptions mOptions;
+
     /** @hide */
     public TransitionInfo(@WindowManager.TransitionOldType int type,
             @WindowManager.TransitionFlags int flags) {
@@ -116,6 +125,7 @@
         mRootLeash = new SurfaceControl();
         mRootLeash.readFromParcel(in);
         mRootOffset.readFromParcel(in);
+        mOptions = in.readTypedObject(AnimationOptions.CREATOR);
     }
 
     @Override
@@ -126,6 +136,7 @@
         dest.writeList(mChanges);
         mRootLeash.writeToParcel(dest, flags);
         mRootOffset.writeToParcel(dest, flags);
+        dest.writeTypedObject(mOptions, flags);
     }
 
     @NonNull
@@ -154,6 +165,10 @@
         mRootOffset.set(offsetLeft, offsetTop);
     }
 
+    public void setAnimationOptions(AnimationOptions options) {
+        mOptions = options;
+    }
+
     public int getType() {
         return mType;
     }
@@ -182,6 +197,10 @@
         return mRootOffset;
     }
 
+    public AnimationOptions getAnimationOptions() {
+        return mOptions;
+    }
+
     @NonNull
     public List<Change> getChanges() {
         return mChanges;
@@ -484,4 +503,146 @@
                     + mStartRotation + "->" + mEndRotation + "}";
         }
     }
+
+    /** Represents animation options during a transition */
+    public static final class AnimationOptions implements Parcelable {
+
+        private int mType;
+        private int mEnterResId;
+        private int mExitResId;
+        private boolean mOverrideTaskTransition;
+        private String mPackageName;
+        private final Rect mTransitionBounds = new Rect();
+        private HardwareBuffer mThumbnail;
+
+        private AnimationOptions(int type) {
+            mType = type;
+        }
+
+        public AnimationOptions(Parcel in) {
+            mType = in.readInt();
+            mEnterResId = in.readInt();
+            mExitResId = in.readInt();
+            mOverrideTaskTransition = in.readBoolean();
+            mPackageName = in.readString();
+            mTransitionBounds.readFromParcel(in);
+            mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
+        }
+
+        public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
+                int exitResId, boolean overrideTaskTransition) {
+            AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
+            options.mPackageName = packageName;
+            options.mEnterResId = enterResId;
+            options.mExitResId = exitResId;
+            options.mOverrideTaskTransition = overrideTaskTransition;
+            return options;
+        }
+
+        public static AnimationOptions makeClipRevealAnimOptions(int startX, int startY, int width,
+                int height) {
+            AnimationOptions options = new AnimationOptions(ANIM_CLIP_REVEAL);
+            options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
+            return options;
+        }
+
+        public static AnimationOptions makeScaleUpAnimOptions(int startX, int startY, int width,
+                int height) {
+            AnimationOptions options = new AnimationOptions(ANIM_SCALE_UP);
+            options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
+            return options;
+        }
+
+        public static AnimationOptions makeThumnbnailAnimOptions(HardwareBuffer srcThumb,
+                int startX, int startY, boolean scaleUp) {
+            AnimationOptions options = new AnimationOptions(
+                    scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN);
+            options.mTransitionBounds.set(startX, startY, startX, startY);
+            options.mThumbnail = srcThumb;
+            return options;
+        }
+
+        public static AnimationOptions makeCrossProfileAnimOptions() {
+            AnimationOptions options = new AnimationOptions(ANIM_OPEN_CROSS_PROFILE_APPS);
+            return options;
+        }
+
+        public int getType() {
+            return mType;
+        }
+
+        public int getEnterResId() {
+            return mEnterResId;
+        }
+
+        public int getExitResId() {
+            return mExitResId;
+        }
+
+        public boolean getOverrideTaskTransition() {
+            return mOverrideTaskTransition;
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        public Rect getTransitionBounds() {
+            return mTransitionBounds;
+        }
+
+        public HardwareBuffer getThumbnail() {
+            return mThumbnail;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mType);
+            dest.writeInt(mEnterResId);
+            dest.writeInt(mExitResId);
+            dest.writeBoolean(mOverrideTaskTransition);
+            dest.writeString(mPackageName);
+            mTransitionBounds.writeToParcel(dest, flags);
+            dest.writeTypedObject(mThumbnail, flags);
+        }
+
+        @NonNull
+        public static final Creator<AnimationOptions> CREATOR =
+                new Creator<AnimationOptions>() {
+                    @Override
+                    public AnimationOptions createFromParcel(Parcel in) {
+                        return new AnimationOptions(in);
+                    }
+
+                    @Override
+                    public AnimationOptions[] newArray(int size) {
+                        return new AnimationOptions[size];
+                    }
+                };
+
+        /** @hide */
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @NonNull
+        private static String typeToString(int mode) {
+            switch(mode) {
+                case ANIM_CUSTOM: return "ANIM_CUSTOM";
+                case ANIM_CLIP_REVEAL: return "ANIM_CLIP_REVEAL";
+                case ANIM_SCALE_UP: return "ANIM_SCALE_UP";
+                case ANIM_THUMBNAIL_SCALE_UP: return "ANIM_THUMBNAIL_SCALE_UP";
+                case ANIM_THUMBNAIL_SCALE_DOWN: return "ANIM_THUMBNAIL_SCALE_DOWN";
+                case ANIM_OPEN_CROSS_PROFILE_APPS: return "ANIM_OPEN_CROSS_PROFILE_APPS";
+                default: return "<unknown:" + mode + ">";
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "{ AnimationOtions type= " + typeToString(mType) + " package=" + mPackageName
+                    + " override=" + mOverrideTaskTransition + " b=" + mTransitionBounds + "}";
+        }
+    }
 }
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index c0af572..8c3dc2e 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.app.WindowConfiguration;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -325,7 +326,8 @@
 
     /**
      * Sets to containers adjacent to each other. Containers below two visible adjacent roots will
-     * be made invisible. This currently only applies to Task containers created by organizer.
+     * be made invisible. This currently only applies to TaskFragment containers created by
+     * organizer.
      * @param root1 the first root.
      * @param root2 the second root.
      */
@@ -378,6 +380,102 @@
     }
 
     /**
+     * Creates a new TaskFragment with the given options.
+     * @param taskFragmentOptions the options used to create the TaskFragment.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction createTaskFragment(
+            @NonNull TaskFragmentCreationParams taskFragmentOptions) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT)
+                        .setTaskFragmentCreationOptions(taskFragmentOptions)
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
+     * Deletes an existing TaskFragment. Any remaining activities below it will be destroyed.
+     * @param taskFragment  the TaskFragment to be removed.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction deleteTaskFragment(
+            @NonNull WindowContainerToken taskFragment) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT)
+                        .setContainer(taskFragment.asBinder())
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
+     * Starts an activity in the TaskFragment.
+     * @param fragmentToken client assigned unique token to create TaskFragment with specified in
+     *                      {@link TaskFragmentCreationParams#fragmentToken}.
+     * @param activityIntent    intent to start the activity.
+     * @param activityOptions    ActivityOptions to start the activity with.
+     * @see android.content.Context#startActivity(Intent, Bundle).
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction startActivityInTaskFragment(
+            @NonNull IBinder fragmentToken, @NonNull Intent activityIntent,
+            @Nullable Bundle activityOptions) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(
+                        HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT)
+                        .setContainer(fragmentToken)
+                        .setActivityIntent(activityIntent)
+                        .setLaunchOptions(activityOptions)
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
+     * Moves an activity into the TaskFragment.
+     * @param fragmentToken client assigned unique token to create TaskFragment with specified in
+     *                      {@link TaskFragmentCreationParams#fragmentToken}.
+     * @param activityToken activity to be reparented.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction reparentActivityToTaskFragment(
+            @NonNull IBinder fragmentToken, @NonNull IBinder activityToken) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(
+                        HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT)
+                        .setReparentContainer(fragmentToken)
+                        .setContainer(activityToken)
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
+     * Reparents all children of one TaskFragment to another.
+     * @param oldParent children of this TaskFragment will be reparented.
+     * @param newParent the new parent TaskFragment to move the children to. If {@code null}, the
+     *                  children will be moved to the leaf Task.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction reparentChildren(
+            @NonNull WindowContainerToken oldParent,
+            @Nullable WindowContainerToken newParent) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN)
+                        .setContainer(oldParent.asBinder())
+                        .setReparentContainer(newParent.asBinder())
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
      * Merges another WCT into this one.
      * @param transfer When true, this will transfer everything from other potentially leaving
      *                 other in an unusable state. When false, other is left alone, but
@@ -705,6 +803,11 @@
         public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4;
         public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5;
         public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6;
+        public static final int HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT = 7;
+        public static final int HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT = 8;
+        public static final int HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 9;
+        public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10;
+        public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -713,75 +816,98 @@
         private final int mType;
 
         // Container we are performing the operation on.
-        private final IBinder mContainer;
+        @Nullable
+        private IBinder mContainer;
 
         // If this is same as mContainer, then only change position, don't reparent.
-        private final IBinder mReparent;
+        @Nullable
+        private IBinder mReparent;
 
         // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
-        private final boolean mToTop;
+        private boolean mToTop;
 
-        final private int[]  mWindowingModes;
-        final private int[] mActivityTypes;
+        @Nullable
+        private int[]  mWindowingModes;
 
-        private final Bundle mLaunchOptions;
+        @Nullable
+        private int[] mActivityTypes;
+
+        @Nullable
+        private Bundle mLaunchOptions;
+
+        @Nullable
+        private Intent mActivityIntent;
+
+        // Used as options for WindowContainerTransaction#createTaskFragment().
+        @Nullable
+        private TaskFragmentCreationParams mTaskFragmentCreationOptions;
 
         public static HierarchyOp createForReparent(
                 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
-            return new HierarchyOp(HIERARCHY_OP_TYPE_REPARENT,
-                    container, reparent, null, null, toTop, null);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
+                    .setContainer(container)
+                    .setReparentContainer(reparent)
+                    .setToTop(toTop)
+                    .build();
         }
 
         public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop) {
-            return new HierarchyOp(HIERARCHY_OP_TYPE_REORDER,
-                    container, container, null, null, toTop, null);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER)
+                    .setContainer(container)
+                    .setReparentContainer(container)
+                    .setToTop(toTop)
+                    .build();
         }
 
         public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent,
                 IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop) {
-            return new HierarchyOp(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT,
-                    currentParent, newParent, windowingModes, activityTypes, onTop, null);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT)
+                    .setContainer(currentParent)
+                    .setReparentContainer(newParent)
+                    .setWindowingModes(windowingModes)
+                    .setActivityTypes(activityTypes)
+                    .setToTop(onTop)
+                    .build();
         }
 
         public static HierarchyOp createForSetLaunchRoot(IBinder container,
                 int[] windowingModes, int[] activityTypes) {
-            return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT,
-                    container, null, windowingModes, activityTypes, false, null);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT)
+                    .setContainer(container)
+                    .setWindowingModes(windowingModes)
+                    .setActivityTypes(activityTypes)
+                    .build();
         }
 
         public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) {
-            return new HierarchyOp(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
-                    root1, root2, null, null, false, null);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
+                    .setContainer(root1)
+                    .setReparentContainer(root2)
+                    .build();
         }
 
         /** Create a hierarchy op for launching a task. */
         public static HierarchyOp createForTaskLaunch(int taskId, @Nullable Bundle options) {
             final Bundle fullOptions = options == null ? new Bundle() : options;
             fullOptions.putInt(LAUNCH_KEY_TASK_ID, taskId);
-            return new HierarchyOp(HIERARCHY_OP_TYPE_LAUNCH_TASK, null, null, null, null, true,
-                    fullOptions);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_LAUNCH_TASK)
+                    .setToTop(true)
+                    .setLaunchOptions(fullOptions)
+                    .build();
         }
 
         /** Create a hierarchy op for setting launch adjacent flag root. */
         public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container,
                 boolean clearRoot) {
-            return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT, container, null,
-                    null, null, clearRoot, null);
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT)
+                    .setContainer(container)
+                    .setToTop(clearRoot)
+                    .build();
         }
 
-
-        private HierarchyOp(int type, @Nullable IBinder container, @Nullable IBinder reparent,
-                int[] windowingModes, int[] activityTypes, boolean toTop,
-                @Nullable Bundle launchOptions) {
+        /** Only creates through {@link Builder}. */
+        private HierarchyOp(int type) {
             mType = type;
-            mContainer = container;
-            mReparent = reparent;
-            mWindowingModes = windowingModes != null ?
-                    Arrays.copyOf(windowingModes, windowingModes.length) : null;
-            mActivityTypes = activityTypes != null ?
-                    Arrays.copyOf(activityTypes, activityTypes.length) : null;
-            mToTop = toTop;
-            mLaunchOptions = launchOptions;
         }
 
         public HierarchyOp(@NonNull HierarchyOp copy) {
@@ -792,6 +918,8 @@
             mWindowingModes = copy.mWindowingModes;
             mActivityTypes = copy.mActivityTypes;
             mLaunchOptions = copy.mLaunchOptions;
+            mActivityIntent = copy.mActivityIntent;
+            mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions;
         }
 
         protected HierarchyOp(Parcel in) {
@@ -802,6 +930,8 @@
             mWindowingModes = in.createIntArray();
             mActivityTypes = in.createIntArray();
             mLaunchOptions = in.readBundle();
+            mActivityIntent = in.readTypedObject(Intent.CREATOR);
+            mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
         }
 
         public int getType() {
@@ -844,6 +974,16 @@
             return mLaunchOptions;
         }
 
+        @Nullable
+        public Intent getActivityIntent() {
+            return mActivityIntent;
+        }
+
+        @Nullable
+        public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
+            return mTaskFragmentCreationOptions;
+        }
+
         @Override
         public String toString() {
             switch (mType) {
@@ -868,6 +1008,19 @@
                 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
                     return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop
                             + "}";
+                case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
+                    return "{CreateTaskFragment: options=" + mTaskFragmentCreationOptions + "}";
+                case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
+                    return "{DeleteTaskFragment: taskFragment=" + mContainer + "}";
+                case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
+                    return "{StartActivityInTaskFragment: fragmentToken=" + mContainer + " intent="
+                            + mActivityIntent + " options=" + mLaunchOptions + "}";
+                case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
+                    return "{ReparentActivityToTaskFragment: fragmentToken=" + mReparent
+                            + " activity=" + mContainer + "}";
+                case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
+                    return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent
+                            + "}";
                 default:
                     return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
                             + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes
@@ -884,6 +1037,8 @@
             dest.writeIntArray(mWindowingModes);
             dest.writeIntArray(mActivityTypes);
             dest.writeBundle(mLaunchOptions);
+            dest.writeTypedObject(mActivityIntent, flags);
+            dest.writeTypedObject(mTaskFragmentCreationOptions, flags);
         }
 
         @Override
@@ -902,5 +1057,96 @@
                 return new HierarchyOp[size];
             }
         };
+
+        private static class Builder {
+
+            private final int mType;
+
+            @Nullable
+            private IBinder mContainer;
+
+            @Nullable
+            private IBinder mReparent;
+
+            private boolean mToTop;
+
+            @Nullable
+            private int[]  mWindowingModes;
+
+            @Nullable
+            private int[] mActivityTypes;
+
+            @Nullable
+            private Bundle mLaunchOptions;
+
+            @Nullable
+            private Intent mActivityIntent;
+
+            @Nullable
+            private TaskFragmentCreationParams mTaskFragmentCreationOptions;
+
+            Builder(int type) {
+                mType = type;
+            }
+
+            Builder setContainer(@Nullable IBinder container) {
+                mContainer = container;
+                return this;
+            }
+
+            Builder setReparentContainer(@Nullable IBinder reparentContainer) {
+                mReparent = reparentContainer;
+                return this;
+            }
+
+            Builder setToTop(boolean toTop) {
+                mToTop = toTop;
+                return this;
+            }
+
+            Builder setWindowingModes(@Nullable int[] windowingModes) {
+                mWindowingModes = windowingModes;
+                return this;
+            }
+
+            Builder setActivityTypes(@Nullable int[] activityTypes) {
+                mActivityTypes = activityTypes;
+                return this;
+            }
+
+            Builder setLaunchOptions(@Nullable Bundle launchOptions) {
+                mLaunchOptions = launchOptions;
+                return this;
+            }
+
+            Builder setActivityIntent(@Nullable Intent activityIntent) {
+                mActivityIntent = activityIntent;
+                return this;
+            }
+
+            Builder setTaskFragmentCreationOptions(
+                    @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
+                mTaskFragmentCreationOptions = taskFragmentCreationOptions;
+                return this;
+            }
+
+            HierarchyOp build() {
+                final HierarchyOp hierarchyOp = new HierarchyOp(mType);
+                hierarchyOp.mContainer = mContainer;
+                hierarchyOp.mReparent = mReparent;
+                hierarchyOp.mWindowingModes = mWindowingModes != null
+                        ? Arrays.copyOf(mWindowingModes, mWindowingModes.length)
+                        : null;
+                hierarchyOp.mActivityTypes = mActivityTypes != null
+                        ? Arrays.copyOf(mActivityTypes, mActivityTypes.length)
+                        : null;
+                hierarchyOp.mToTop = mToTop;
+                hierarchyOp.mLaunchOptions = mLaunchOptions;
+                hierarchyOp.mActivityIntent = mActivityIntent;
+                hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
+
+                return hierarchyOp;
+            }
+        }
     }
 }
diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java
index 901625b..69d7b4c 100644
--- a/core/java/android/window/WindowContext.java
+++ b/core/java/android/window/WindowContext.java
@@ -57,8 +57,14 @@
      *
      * @param base Base {@link Context} for this new instance.
      * @param type Window type to be used with this context.
-     * @param options A bundle used to pass window-related options.
-     *
+     * @param options A bundle used to pass window-related options. For example, on device with
+     *                multiple DisplayAreaGroups, one may specify the RootDisplayArea for the window
+     *                using {@link DisplayAreaOrganizer#KEY_ROOT_DISPLAY_AREA_ID} in the options.
+     *                Example usage:
+     *                Bundle options = new Bundle();
+     *                options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
+     *                Context windowContext = context.createWindowContext(display, type, options);
+     * @see DisplayAreaInfo#rootDisplayAreaId
      * @hide
      */
     public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java
index b8619fb..5171adf 100644
--- a/core/java/android/window/WindowProviderService.java
+++ b/core/java/android/window/WindowProviderService.java
@@ -36,7 +36,6 @@
 import android.view.WindowManager.LayoutParams.WindowType;
 import android.view.WindowManagerImpl;
 
-// TODO(b/159767464): handle #onConfigurationChanged(Configuration)
 /**
  * A {@link Service} responsible for showing a non-activity window, such as software keyboards or
  * accessibility overlay windows. This {@link Service} has similar behavior to
@@ -54,6 +53,7 @@
     private final WindowTokenClient mWindowToken = new WindowTokenClient();
     private final WindowContextController mController = new WindowContextController(mWindowToken);
     private WindowManager mWindowManager;
+    private boolean mInitialized;
 
     /**
      * Returns the type of this {@link WindowProviderService}.
@@ -90,6 +90,20 @@
     }
 
     /**
+     * Returns the display ID to launch this {@link WindowProviderService}.
+     *
+     * @hide
+     */
+    @TestApi
+    @SuppressLint({"OnNameExpected"})
+    // Suppress the lint because it is not a callback and users may override this API to provide
+    // display.
+    @NonNull
+    public int getInitialDisplayId() {
+        return DEFAULT_DISPLAY;
+    }
+
+    /**
      * Attaches this WindowProviderService to the {@code windowToken}.
      *
      * @hide
@@ -104,19 +118,22 @@
     public final Context createServiceBaseContext(ActivityThread mainThread,
             LoadedApk packageInfo) {
         final Context context = super.createServiceBaseContext(mainThread, packageInfo);
-        // Always associate with the default display at initialization.
-        final Display defaultDisplay = context.getSystemService(DisplayManager.class)
-                .getDisplay(DEFAULT_DISPLAY);
-        return context.createTokenContext(mWindowToken, defaultDisplay);
+        final Display display = context.getSystemService(DisplayManager.class)
+                .getDisplay(getInitialDisplayId());
+        return context.createTokenContext(mWindowToken, display);
     }
 
-    @CallSuper
+    /** @hide */
     @Override
-    public void onCreate() {
-        super.onCreate();
-        mWindowToken.attachContext(this);
-        mController.attachToDisplayArea(getWindowType(), getDisplayId(), getWindowContextOptions());
-        mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this);
+    protected void attachBaseContext(Context newBase) {
+        super.attachBaseContext(newBase);
+        if (!mInitialized) {
+            mWindowToken.attachContext(this);
+            mController.attachToDisplayArea(getWindowType(), getDisplayId(),
+                    getWindowContextOptions());
+            mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this);
+            mInitialized = true;
+        }
     }
 
     @SuppressLint("OnNameExpected")
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 6abf557..c32a268 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -15,14 +15,22 @@
  */
 package android.window;
 
+import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets;
+import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
+import static android.window.ConfigurationHelper.isDifferentDisplay;
+import static android.window.ConfigurationHelper.shouldUpdateResources;
+
 import android.annotation.NonNull;
 import android.app.ActivityThread;
 import android.app.IWindowToken;
 import android.app.ResourcesManager;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.inputmethodservice.AbstractInputMethodService;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.Log;
 
 import java.lang.ref.WeakReference;
 
@@ -33,11 +41,13 @@
  * {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}.
  *
  * @see WindowContext
- * @see android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, Bundle)
+ * @see android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, Bundle)
  *
  * @hide
  */
 public class WindowTokenClient extends IWindowToken.Stub {
+    private static final String TAG = WindowTokenClient.class.getSimpleName();
+
     /**
      * Attached {@link Context} for this window token to update configuration and resources.
      * Initialized by {@link #attachContext(Context)}.
@@ -46,11 +56,15 @@
 
     private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
 
+    private final Configuration mConfiguration = new Configuration();
+
+    private boolean mShouldDumpConfigForIme;
+
     /**
      * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
      * can only attach one {@link Context}.
      * <p>This method must be called before invoking
-     * {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int,
+     * {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int,
      * Bundle, boolean)}.<p/>
      *
      * @param context context to be attached
@@ -61,6 +75,9 @@
             throw new IllegalStateException("Context is already attached.");
         }
         mContextRef = new WeakReference<>(context);
+        mConfiguration.setTo(context.getResources().getConfiguration());
+        mShouldDumpConfigForIme = Build.IS_DEBUGGABLE
+                && context instanceof AbstractInputMethodService;
     }
 
     @Override
@@ -69,17 +86,48 @@
         if (context == null) {
             return;
         }
-        final int currentDisplayId = context.getDisplayId();
-        final boolean displayChanged = newDisplayId != currentDisplayId;
-        final Configuration config = context.getResources().getConfiguration();
-        final boolean configChanged = config.diff(newConfig) != 0;
-        if (displayChanged || configChanged) {
+        final boolean displayChanged = isDifferentDisplay(context.getDisplayId(), newDisplayId);
+        final boolean shouldUpdateResources = shouldUpdateResources(this, mConfiguration,
+                newConfig, newConfig /* overrideConfig */, displayChanged,
+                null /* configChanged */);
+
+        if (!shouldUpdateResources && mShouldDumpConfigForIme) {
+            Log.d(TAG, "Configuration not dispatch to IME because configuration is up"
+                    + " to date. Current config=" + context.getResources().getConfiguration()
+                    + ", reported config=" + mConfiguration
+                    + ", updated config=" + newConfig);
+        }
+
+        if (shouldUpdateResources) {
             // TODO(ag/9789103): update resource manager logic to track non-activity tokens
             mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
+
             if (context instanceof WindowContext) {
                 ActivityThread.currentActivityThread().getHandler().post(
                         () -> ((WindowContext) context).dispatchConfigurationChanged(newConfig));
             }
+
+            // Dispatch onConfigurationChanged only if there's a significant public change to
+            // make it compatible with the original behavior.
+            final Configuration[] sizeConfigurations = context.getResources()
+                    .getSizeConfigurations();
+            final SizeConfigurationBuckets buckets = sizeConfigurations != null
+                    ? new SizeConfigurationBuckets(sizeConfigurations) : null;
+            final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets);
+
+            if (context instanceof WindowProviderService && diff != 0) {
+                ActivityThread.currentActivityThread().getHandler().post(() ->
+                        ((WindowProviderService) context).onConfigurationChanged(newConfig));
+            }
+            freeTextLayoutCachesIfNeeded(diff);
+            if (diff == 0 && mShouldDumpConfigForIme) {
+                Log.d(TAG, "Configuration not dispatch to IME because configuration has no "
+                        + " public difference with updated config. "
+                        + " Current config=" + context.getResources().getConfiguration()
+                        + ", reported config=" + mConfiguration
+                        + ", updated config=" + newConfig);
+            }
+            mConfiguration.setTo(newConfig);
         }
         if (displayChanged) {
             context.updateDisplay(newDisplayId);
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index 4b4e20f..6a976ef 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -20,16 +20,23 @@
 import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Build;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.ParcelableSpan;
+import android.text.Spanned;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityManager;
 
+import libcore.util.EmptyArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -39,7 +46,25 @@
  * Collection of utilities for accessibility service.
  */
 public final class AccessibilityUtils {
-    private AccessibilityUtils() {}
+    private AccessibilityUtils() {
+    }
+
+    /** @hide */
+    @IntDef(value = {
+            NONE,
+            TEXT,
+            PARCELABLE_SPAN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface A11yTextChangeType {
+    }
+
+    /** Specifies no content has been changed for accessibility. */
+    public static final int NONE = 0;
+    /** Specifies some readable sequence has been changed. */
+    public static final int TEXT = 1;
+    /** Specifies some parcelable spans has been changed. */
+    public static final int PARCELABLE_SPAN = 2;
 
     /**
      * Returns the set of enabled accessibility services for userId. If there are no
@@ -168,4 +193,55 @@
                 Settings.Secure.USER_SETUP_COMPLETE, /* def= */ 0, UserHandle.USER_CURRENT)
                 != /* false */ 0;
     }
+
+    /**
+     * Returns the text change type for accessibility. It only cares about readable sequence changes
+     * or {@link ParcelableSpan} changes which are able to pass via IPC.
+     *
+     * @param before The CharSequence before changing
+     * @param after  The CharSequence after changing
+     * @return Returns {@code TEXT} for readable sequence changes or {@code PARCELABLE_SPAN} for
+     * ParcelableSpan changes. Otherwise, returns {@code NONE}.
+     */
+    @A11yTextChangeType
+    public static int textOrSpanChanged(CharSequence before, CharSequence after) {
+        if (!TextUtils.equals(before, after)) {
+            return TEXT;
+        }
+        if (before instanceof Spanned || after instanceof Spanned) {
+            if (!parcelableSpansEquals(before, after)) {
+                return PARCELABLE_SPAN;
+            }
+        }
+        return NONE;
+    }
+
+    private static boolean parcelableSpansEquals(CharSequence before, CharSequence after) {
+        Object[] spansA = EmptyArray.OBJECT;
+        Object[] spansB = EmptyArray.OBJECT;
+        Spanned a = null;
+        Spanned b = null;
+        if (before instanceof Spanned) {
+            a = (Spanned) before;
+            spansA = a.getSpans(0, a.length(), ParcelableSpan.class);
+        }
+        if (after instanceof Spanned) {
+            b = (Spanned) after;
+            spansB = b.getSpans(0, b.length(), ParcelableSpan.class);
+        }
+        if (spansA.length != spansB.length) {
+            return false;
+        }
+        for (int i = 0; i < spansA.length; ++i) {
+            final Object thisSpan = spansA[i];
+            final Object otherSpan = spansB[i];
+            if ((thisSpan.getClass() != otherSpan.getClass())
+                    || (a.getSpanStart(thisSpan) != b.getSpanStart(otherSpan))
+                    || (a.getSpanEnd(thisSpan) != b.getSpanEnd(otherSpan))
+                    || (a.getSpanFlags(thisSpan) != b.getSpanFlags(otherSpan))) {
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 7000ed7..3f0b6b3 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2120,10 +2120,10 @@
                     + " resultList.size()=" + resultList.size()
                     + " appTargets.size()=" + appTargets.size());
         }
-
+        Context selectedProfileContext = createContextAsUser(userHandle, 0 /* flags */);
         for (int i = resultList.size() - 1; i >= 0; i--) {
             final String packageName = resultList.get(i).getTargetComponent().getPackageName();
-            if (!isPackageEnabled(packageName)) {
+            if (!isPackageEnabled(selectedProfileContext, packageName)) {
                 resultList.remove(i);
                 if (appTargets != null) {
                     appTargets.remove(i);
@@ -2175,13 +2175,13 @@
         mChooserHandler.sendMessage(msg);
     }
 
-    private boolean isPackageEnabled(String packageName) {
+    private boolean isPackageEnabled(Context context, String packageName) {
         if (TextUtils.isEmpty(packageName)) {
             return false;
         }
         ApplicationInfo appInfo;
         try {
-            appInfo = getPackageManager().getApplicationInfo(packageName, 0);
+            appInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
         } catch (NameNotFoundException e) {
             return false;
         }
diff --git a/core/java/com/android/internal/content/om/OWNERS b/core/java/com/android/internal/content/om/OWNERS
new file mode 100644
index 0000000..44fd9fd
--- /dev/null
+++ b/core/java/com/android/internal/content/om/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 568631
+include /core/java/android/content/om/OWNERS
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dab3e9f..b17df2a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5091,46 +5091,48 @@
     }
 
     public void notePowerSaveModeLocked(boolean enabled) {
-        notePowerSaveModeLocked(enabled, mClocks.elapsedRealtime(), mClocks.uptimeMillis(), false);
+        notePowerSaveModeLocked(enabled, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
     }
 
     /**
-     * Handles power save mode state changes.
+     * Toggles the power save mode state.
      */
-    public void notePowerSaveModeLocked(boolean enabled, long elapsedRealtimeMs, long uptimeMs,
-            boolean forceLog) {
+    public void notePowerSaveModeLockedInit(boolean enabled, long elapsedRealtimeMs,
+            long uptimeMs) {
+        if (mPowerSaveModeEnabled != enabled) {
+            notePowerSaveModeLocked(enabled, elapsedRealtimeMs, uptimeMs);
+        } else {
+            // Log an initial value for BATTERY_SAVER_MODE_STATE_CHANGED in order to
+            // allow the atom to read all future state changes.
+            FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED,
+                    enabled
+                        ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON
+                        : FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__OFF);
+        }
+    }
+
+    public void notePowerSaveModeLocked(boolean enabled, long elapsedRealtimeMs, long uptimeMs) {
         if (mPowerSaveModeEnabled != enabled) {
             int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
-            mModStepMode |= (mCurStepMode & STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
-            mCurStepMode = (mCurStepMode & ~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
+            mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
+            mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
             mPowerSaveModeEnabled = enabled;
             if (enabled) {
                 mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
-                if (DEBUG_HISTORY) {
-                    Slog.v(TAG, "Power save mode enabled to: "
-                            + Integer.toHexString(mHistoryCur.states2));
-                }
+                if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: "
+                        + Integer.toHexString(mHistoryCur.states2));
                 mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
                 mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG;
-                if (DEBUG_HISTORY) {
-                    Slog.v(TAG, "Power save mode disabled to: "
-                            + Integer.toHexString(mHistoryCur.states2));
-                }
+                if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: "
+                        + Integer.toHexString(mHistoryCur.states2));
                 mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtimeMs);
             }
             addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED,
                     enabled
-                            ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON
-                            : FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__OFF);
-        } else if (forceLog) {
-            // Log an initial value for BATTERY_SAVER_MODE_STATE_CHANGED in order to
-            // allow the atom to read all future state changes.
-            FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED,
-                    enabled
-                            ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON
-                            : FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__OFF);
+                        ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON
+                        : FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__OFF);
         }
     }
 
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 60a8d80..d3224b1 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -16,16 +16,20 @@
 
 package com.android.internal.policy;
 
+import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
+import static android.view.WindowManager.TRANSIT_OPEN;
 
+import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -34,12 +38,18 @@
 import android.content.res.ResourceId;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Picture;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.hardware.HardwareBuffer;
 import android.os.SystemProperties;
 import android.util.Slog;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.TransitionOldType;
+import android.view.WindowManager.TransitionType;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
@@ -56,11 +66,17 @@
 
 /** @hide */
 public class TransitionAnimation {
+    public static final int WALLPAPER_TRANSITION_NONE = 0;
+    public static final int WALLPAPER_TRANSITION_OPEN = 1;
+    public static final int WALLPAPER_TRANSITION_CLOSE = 2;
+    public static final int WALLPAPER_TRANSITION_INTRA_OPEN = 3;
+    public static final int WALLPAPER_TRANSITION_INTRA_CLOSE = 4;
+
     // These are the possible states for the enter/exit activities during a thumbnail transition
-    public static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
-    public static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
-    public static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
-    public static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
+    private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
+    private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
+    private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
+    private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
 
     /**
      * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
@@ -72,9 +88,15 @@
 
     public static final int DEFAULT_APP_TRANSITION_DURATION = 336;
 
+    /** Fraction of animation at which the recents thumbnail stays completely transparent */
+    private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
 
+    /** Interpolator to be used for animations that respond directly to a touch */
+    static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
     private static final String DEFAULT_PACKAGE = "android";
 
     private final Context mContext;
@@ -86,7 +108,9 @@
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
     private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
     private final Interpolator mDecelerateInterpolator;
+    private final Interpolator mFastOutLinearInInterpolator;
     private final Interpolator mLinearOutSlowInInterpolator;
+    private final Interpolator mThumbnailFadeInInterpolator;
     private final Interpolator mThumbnailFadeOutInterpolator;
     private final Rect mTmpFromClipRect = new Rect();
     private final Rect mTmpToClipRect = new Rect();
@@ -107,8 +131,19 @@
 
         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.decelerate_cubic);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.linear_out_slow_in);
+        mThumbnailFadeInInterpolator = input -> {
+            // Linear response for first fraction, then complete after that.
+            if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
+                return 0f;
+            }
+            float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION)
+                    / (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
+            return mFastOutLinearInInterpolator.getInterpolation(t);
+        };
         mThumbnailFadeOutInterpolator = input -> {
             // Linear response for first fraction, then complete after that.
             if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
@@ -181,6 +216,13 @@
                 DEFAULT_PACKAGE, com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
     }
 
+    @Nullable
+    public Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
+        final Animation animation = loadCrossProfileAppThumbnailEnterAnimation();
+        return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
+                appRect.height(), 0, null);
+    }
+
     /** Load animation by resource Id from specific package. */
     @Nullable
     public Animation loadAnimationRes(String packageName, int resId) {
@@ -347,8 +389,15 @@
         }
     }
 
-    public Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
-            Rect displayFrame, Rect startRect) {
+    public Animation createClipRevealAnimationLocked(@TransitionType int transit,
+            int wallpaperTransit, boolean enter, Rect appFrame, Rect displayFrame, Rect startRect) {
+        return createClipRevealAnimationLockedCompat(
+                getTransitCompatType(transit, wallpaperTransit), enter, appFrame, displayFrame,
+                startRect);
+    }
+
+    public Animation createClipRevealAnimationLockedCompat(@TransitionOldType int transit,
+            boolean enter, Rect appFrame, Rect displayFrame, Rect startRect) {
         final Animation anim;
         if (enter) {
             final int appWidth = appFrame.width();
@@ -458,8 +507,14 @@
         return anim;
     }
 
-    public Animation createScaleUpAnimationLocked(int transit, boolean enter,
-            Rect containingFrame, Rect startRect) {
+    public Animation createScaleUpAnimationLocked(@TransitionType int transit, int wallpaperTransit,
+            boolean enter, Rect containingFrame, Rect startRect) {
+        return createScaleUpAnimationLockedCompat(getTransitCompatType(transit, wallpaperTransit),
+                enter, containingFrame, startRect);
+    }
+
+    public Animation createScaleUpAnimationLockedCompat(@TransitionOldType int transit,
+            boolean enter, Rect containingFrame, Rect startRect) {
         Animation a;
         setupDefaultNextAppTransitionStartRect(startRect, mTmpRect);
         final int appWidth = containingFrame.width();
@@ -514,12 +569,19 @@
         return a;
     }
 
+    public Animation createThumbnailEnterExitAnimationLocked(boolean enter, boolean scaleUp,
+            Rect containingFrame, @TransitionType int transit, int wallpaperTransit,
+            HardwareBuffer thumbnailHeader, Rect startRect) {
+        return createThumbnailEnterExitAnimationLockedCompat(enter, scaleUp, containingFrame,
+                getTransitCompatType(transit, wallpaperTransit), thumbnailHeader, startRect);
+    }
+
     /**
      * This animation is created when we are doing a thumbnail transition, for the activity that is
      * leaving, and the activity that is entering.
      */
-    public Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState,
-            Rect containingFrame, int transit, HardwareBuffer thumbnailHeader,
+    public Animation createThumbnailEnterExitAnimationLockedCompat(boolean enter, boolean scaleUp,
+            Rect containingFrame, @TransitionOldType int transit, HardwareBuffer thumbnailHeader,
             Rect startRect) {
         final int appWidth = containingFrame.width();
         final int appHeight = containingFrame.height();
@@ -529,6 +591,7 @@
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
         final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
+        final int thumbTransitState = getThumbnailTransitionState(enter, scaleUp);
 
         switch (thumbTransitState) {
             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
@@ -587,8 +650,8 @@
      * This alternate animation is created when we are doing a thumbnail transition, for the
      * activity that is leaving, and the activity that is entering.
      */
-    public Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
-            int orientation, int transit, Rect containingFrame, Rect contentInsets,
+    public Animation createAspectScaledThumbnailEnterExitAnimationLocked(boolean enter,
+            boolean scaleUp, int orientation, int transit, Rect containingFrame, Rect contentInsets,
             @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
             Rect startRect, Rect defaultStartRect) {
         Animation a;
@@ -601,11 +664,11 @@
         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
         final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
         final int thumbStartY = mTmpRect.top - containingFrame.top;
+        final int thumbTransitState = getThumbnailTransitionState(enter, scaleUp);
 
         switch (thumbTransitState) {
             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
-                final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
                 if (freeform && scaleUp) {
                     a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
                             containingFrame, surfaceInsets, startRect, defaultStartRect);
@@ -720,10 +783,151 @@
     }
 
     /**
+     * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
+     * when a thumbnail is specified with the pending animation override.
+     */
+    public Animation createThumbnailAspectScaleAnimationLocked(Rect appRect,
+            @Nullable Rect contentInsets, HardwareBuffer thumbnailHeader, int orientation,
+            Rect startRect, Rect defaultStartRect, boolean scaleUp) {
+        Animation a;
+        final int thumbWidthI = thumbnailHeader.getWidth();
+        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
+        final int thumbHeightI = thumbnailHeader.getHeight();
+        final int appWidth = appRect.width();
+
+        float scaleW = appWidth / thumbWidth;
+        getNextAppTransitionStartRect(startRect, defaultStartRect, mTmpRect);
+        final float fromX;
+        float fromY;
+        final float toX;
+        float toY;
+        final float pivotX;
+        final float pivotY;
+        if (shouldScaleDownThumbnailTransition(orientation)) {
+            fromX = mTmpRect.left;
+            fromY = mTmpRect.top;
+
+            // For the curved translate animation to work, the pivot points needs to be at the
+            // same absolute position as the one from the real surface.
+            toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
+            toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
+            pivotX = mTmpRect.width() / 2;
+            pivotY = appRect.height() / 2 / scaleW;
+            if (mGridLayoutRecentsEnabled) {
+                // In the grid layout, the header is displayed above the thumbnail instead of
+                // overlapping it.
+                fromY -= thumbHeightI;
+                toY -= thumbHeightI * scaleW;
+            }
+        } else {
+            pivotX = 0;
+            pivotY = 0;
+            fromX = mTmpRect.left;
+            fromY = mTmpRect.top;
+            toX = appRect.left;
+            toY = appRect.top;
+        }
+        if (scaleUp) {
+            // Animation up from the thumbnail to the full screen
+            Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
+            scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            Animation alpha = new AlphaAnimation(1f, 0f);
+            alpha.setInterpolator(mThumbnailFadeOutInterpolator);
+            alpha.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
+            translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+            translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+
+            mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
+            mTmpToClipRect.set(appRect);
+
+            // Containing frame is in screen space, but we need the clip rect in the
+            // app space.
+            mTmpToClipRect.offsetTo(0, 0);
+            mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
+            mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
+
+            if (contentInsets != null) {
+                mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
+                        (int) (-contentInsets.top * scaleW),
+                        (int) (-contentInsets.right * scaleW),
+                        (int) (-contentInsets.bottom * scaleW));
+            }
+
+            Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+            clipAnim.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+            clipAnim.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+
+            // This AnimationSet uses the Interpolators assigned above.
+            AnimationSet set = new AnimationSet(false);
+            set.addAnimation(scale);
+            if (!mGridLayoutRecentsEnabled) {
+                // In the grid layout, the header should be shown for the whole animation.
+                set.addAnimation(alpha);
+            }
+            set.addAnimation(translate);
+            set.addAnimation(clipAnim);
+            a = set;
+        } else {
+            // Animation down from the full screen to the thumbnail
+            Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
+            scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            Animation alpha = new AlphaAnimation(0f, 1f);
+            alpha.setInterpolator(mThumbnailFadeInInterpolator);
+            alpha.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+            Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
+            translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+            translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+
+            // This AnimationSet uses the Interpolators assigned above.
+            AnimationSet set = new AnimationSet(false);
+            set.addAnimation(scale);
+            if (!mGridLayoutRecentsEnabled) {
+                // In the grid layout, the header should be shown for the whole animation.
+                set.addAnimation(alpha);
+            }
+            set.addAnimation(translate);
+            a = set;
+
+        }
+        return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
+                null);
+    }
+
+    /**
+     * Creates an overlay with a background color and a thumbnail for the cross profile apps
+     * animation.
+     */
+    public HardwareBuffer createCrossProfileAppsThumbnail(
+            @DrawableRes int thumbnailDrawableRes, Rect frame) {
+        final int width = frame.width();
+        final int height = frame.height();
+
+        final Picture picture = new Picture();
+        final Canvas canvas = picture.beginRecording(width, height);
+        canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
+        final int thumbnailSize = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
+        final Drawable drawable = mContext.getDrawable(thumbnailDrawableRes);
+        drawable.setBounds(
+                (width - thumbnailSize) / 2,
+                (height - thumbnailSize) / 2,
+                (width + thumbnailSize) / 2,
+                (height + thumbnailSize) / 2);
+        drawable.setTint(mContext.getColor(android.R.color.white));
+        drawable.draw(canvas);
+        picture.endRecording();
+
+        return Bitmap.createBitmap(picture).getHardwareBuffer();
+    }
+
+    /**
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
     private Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight,
-            int transit) {
+            @TransitionOldType int transit) {
         // Pick the desired duration.  If this is an inter-activity transition,
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
@@ -820,6 +1024,22 @@
         return anim;
     }
 
+    private static @TransitionOldType int getTransitCompatType(@TransitionType int transit,
+            int wallpaperTransit) {
+        if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
+            return TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
+            return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
+        } else if (transit == TRANSIT_OPEN) {
+            return TRANSIT_OLD_ACTIVITY_OPEN;
+        } else if (transit == TRANSIT_CLOSE) {
+            return TRANSIT_OLD_ACTIVITY_CLOSE;
+        }
+
+        // We only do some special handle for above type, so use type NONE for default behavior.
+        return TRANSIT_OLD_NONE;
+    }
+
     /**
      * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
      * the start rect is outside of the target rect, and there is a lot of movement going on.
@@ -843,10 +1063,33 @@
     }
 
     /**
+     * Return the current thumbnail transition state.
+     */
+    private int getThumbnailTransitionState(boolean enter, boolean scaleUp) {
+        if (enter) {
+            if (scaleUp) {
+                return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
+            } else {
+                return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
+            }
+        } else {
+            if (scaleUp) {
+                return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
+            } else {
+                return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
+            }
+        }
+    }
+
+    /**
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
-    private static Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth,
+    public static Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth,
             int appHeight, long duration, Interpolator interpolator) {
+        if (a == null) {
+            return null;
+        }
+
         if (duration > 0) {
             a.setDuration(duration);
         }
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index a045451..5b68159 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -1,5 +1,6 @@
 per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com
 per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
+per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
 per-file Protocol* = etancohen@google.com, lorenzo@google.com
 per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
 per-file DataClass* = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 125182c..958205f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -230,6 +230,7 @@
                 "libbinderthreadstateutils",
                 "libdmabufinfo",
                 "libgif",
+                "libgui_window_info_static",
                 "libseccomp_policy",
                 "libgrallocusage",
                 "libscrypt_static",
@@ -370,6 +371,7 @@
                 "libinput",
                 "libbinderthreadstateutils",
                 "libsqlite",
+                "libgui_window_info_static",
             ],
             shared_libs: [
                 // libbinder needs to be shared since it has global state
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h
index ec99d6d..7eb7ac4 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.h
+++ b/core/jni/android_hardware_input_InputApplicationHandle.h
@@ -19,7 +19,7 @@
 
 #include <string>
 
-#include <input/InputApplication.h>
+#include <gui/InputApplication.h>
 
 #include <nativehelper/JNIHelp.h>
 #include "jni.h"
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 463d909..3a09562 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -26,14 +26,17 @@
 #include <ui/Region.h>
 #include <utils/threads.h>
 
+#include <gui/WindowInfo.h>
 #include "android_hardware_input_InputApplicationHandle.h"
 #include "android_util_Binder.h"
 #include "core_jni_helpers.h"
-#include "input/InputWindow.h"
 #include "jni.h"
 
 namespace android {
 
+using gui::TouchOcclusionMode;
+using gui::WindowInfo;
+
 struct WeakRefHandleField {
     jfieldID ctrl;
     jmethodID get;
@@ -66,7 +69,6 @@
     jfieldID packageName;
     jfieldID inputFeatures;
     jfieldID displayId;
-    jfieldID portalToDisplayId;
     jfieldID replaceTouchableRegionWithCrop;
     WeakRefHandleField touchableRegionSurfaceControl;
 } gInputWindowHandleClassInfo;
@@ -115,9 +117,9 @@
 
     mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
 
-    mInfo.flags = Flags<InputWindowInfo::Flag>(
+    mInfo.flags = Flags<WindowInfo::Flag>(
             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
-    mInfo.type = static_cast<InputWindowInfo::Type>(
+    mInfo.type = static_cast<WindowInfo::Type>(
             env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
     mInfo.dispatchingTimeout = std::chrono::milliseconds(
             env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
@@ -159,12 +161,10 @@
     mInfo.ownerUid = env->GetIntField(obj,
             gInputWindowHandleClassInfo.ownerUid);
     mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
-    mInfo.inputFeatures = static_cast<InputWindowInfo::Feature>(
+    mInfo.inputFeatures = static_cast<WindowInfo::Feature>(
             env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures));
     mInfo.displayId = env->GetIntField(obj,
             gInputWindowHandleClassInfo.displayId);
-    mInfo.portalToDisplayId = env->GetIntField(obj,
-            gInputWindowHandleClassInfo.portalToDisplayId);
 
     jobject inputApplicationHandleObj = env->GetObjectField(obj,
             gInputWindowHandleClassInfo.inputApplicationHandle);
@@ -348,9 +348,6 @@
     GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
             "displayId", "I");
 
-    GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz,
-            "portalToDisplayId", "I");
-
     GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
             "replaceTouchableRegionWithCrop", "Z");
 
diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h
index de5bd6e..635480fc 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.h
+++ b/core/jni/android_hardware_input_InputWindowHandle.h
@@ -17,14 +17,14 @@
 #ifndef _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H
 #define _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H
 
-#include <input/InputWindow.h>
+#include <gui/WindowInfo.h>
 
 #include <nativehelper/JNIHelp.h>
 #include "jni.h"
 
 namespace android {
 
-class NativeInputWindowHandle : public InputWindowHandle {
+class NativeInputWindowHandle : public gui::WindowInfoHandle {
 public:
     NativeInputWindowHandle(jweak objWeak);
     virtual ~NativeInputWindowHandle();
@@ -37,7 +37,6 @@
     jweak mObjWeak;
 };
 
-
 extern sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
         JNIEnv* env, jobject inputWindowHandleObj);
 
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index b40491a..f44e829 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -50,8 +50,7 @@
 }
 
 void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
-                         jstring devOptIn, jobjectArray featuresObj, jobject rulesFd,
-                         jlong rulesOffset, jlong rulesLength) {
+                         jstring devOptIn, jobjectArray featuresObj) {
     ScopedUtfChars pathChars(env, path);
     ScopedUtfChars appNameChars(env, appName);
     ScopedUtfChars devOptInChars(env, devOptIn);
@@ -74,11 +73,8 @@
         }
     }
 
-    int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
-
     android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
-                                                     devOptInChars.c_str(), features,
-                                                     rulesFd_native, rulesOffset, rulesLength);
+                                                     devOptInChars.c_str(), features);
 }
 
 bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
@@ -124,8 +120,7 @@
         {"setInjectLayersPrSetDumpable", "()Z",
          reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
         {"setAngleInfo",
-         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/io/"
-         "FileDescriptor;JJ)V",
+         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
          reinterpret_cast<void*>(setAngleInfo_native)},
         {"getShouldUseAngle", "(Ljava/lang/String;)Z",
          reinterpret_cast<void*>(shouldUseAngle_native)},
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 6971301..21db198 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -22,6 +22,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
 #include <attestation/HmacKeyManager.h>
+#include <gui/constants.h>
 #include <input/Input.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <utils/Log.h>
@@ -56,6 +57,8 @@
     jfieldID toolMajor;
     jfieldID toolMinor;
     jfieldID orientation;
+    jfieldID relativeX;
+    jfieldID relativeY;
 } gPointerCoordsClassInfo;
 
 static struct {
@@ -212,6 +215,12 @@
             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
+    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
+                                      env->GetFloatField(pointerCoordsObj,
+                                                         gPointerCoordsClassInfo.relativeX));
+    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
+                                      env->GetFloatField(pointerCoordsObj,
+                                                         gPointerCoordsClassInfo.relativeY));
 
     BitSet64 bits =
             BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits));
@@ -261,6 +270,12 @@
     float rawY = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y);
     vec2 transformed = transform.transform(rawX, rawY);
 
+    float rawRelX = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
+    float rawRelY = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
+    // Apply only rotation and scale, not translation.
+    const vec2 transformedOrigin = transform.transform(0, 0);
+    const vec2 transformedRel = transform.transform(rawRelX, rawRelY) - transformedOrigin;
+
     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x, transformed.x);
     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y, transformed.y);
     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure,
@@ -277,6 +292,8 @@
             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR));
     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation,
             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.relativeX, transformedRel.x);
+    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.relativeY, transformedRel.y);
 
     uint64_t outBits = 0;
     BitSet64 bits = BitSet64(rawPointerCoords->bits);
@@ -289,6 +306,8 @@
     bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MAJOR);
     bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MINOR);
     bits.clearBit(AMOTION_EVENT_AXIS_ORIENTATION);
+    bits.clearBit(AMOTION_EVENT_AXIS_RELATIVE_X);
+    bits.clearBit(AMOTION_EVENT_AXIS_RELATIVE_Y);
     if (!bits.isEmpty()) {
         uint32_t packedAxesCount = bits.count();
         jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount,
@@ -378,9 +397,9 @@
                       flags, edgeFlags, metaState, buttonState,
                       static_cast<MotionClassification>(classification), transform, xPrecision,
                       yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
-                      AMOTION_EVENT_INVALID_DISPLAY_SIZE, downTimeNanos, eventTimeNanos,
-                      pointerCount, pointerProperties, rawPointerCoords);
+                      AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
+                      INVALID_DISPLAY_SIZE, downTimeNanos, eventTimeNanos, pointerCount,
+                      pointerProperties, rawPointerCoords);
 
     return reinterpret_cast<jlong>(event.release());
 }
@@ -872,6 +891,8 @@
     gPointerCoordsClassInfo.toolMajor = GetFieldIDOrDie(env, clazz, "toolMajor", "F");
     gPointerCoordsClassInfo.toolMinor = GetFieldIDOrDie(env, clazz, "toolMinor", "F");
     gPointerCoordsClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "F");
+    gPointerCoordsClassInfo.relativeX = GetFieldIDOrDie(env, clazz, "relativeX", "F");
+    gPointerCoordsClassInfo.relativeY = GetFieldIDOrDie(env, clazz, "relativeY", "F");
 
     clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerProperties");
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e9e79dc3..455c70e 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -62,6 +62,8 @@
 
 namespace android {
 
+using gui::FocusRequest;
+
 static void doThrowNPE(JNIEnv* env) {
     jniThrowNullPointerException(env, NULL);
 }
@@ -882,8 +884,9 @@
 }
 
 static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
-    sp<IBinder> token =
-            SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId));
+    const auto id = DisplayId::fromValue<PhysicalDisplayId>(physicalDisplayId);
+    if (!id) return nullptr;
+    sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(*id);
     return javaObjectForIBinder(env, token);
 }
 
@@ -1006,6 +1009,17 @@
     }
 }
 
+static void nativeSetDisplayFlags(JNIEnv* env, jclass clazz, jlong transactionObj, jobject tokenObj,
+                                  jint flags) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return;
+
+    {
+        auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+        transaction->setDisplayFlags(token, flags);
+    }
+}
+
 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
         jlong transactionObj,
         jobject tokenObj, jint orientation,
@@ -1873,6 +1887,8 @@
             (void*)nativeSetDisplaySurface },
     {"nativeSetDisplayLayerStack", "(JLandroid/os/IBinder;I)V",
             (void*)nativeSetDisplayLayerStack },
+    {"nativeSetDisplayFlags", "(JLandroid/os/IBinder;I)V",
+            (void*)nativeSetDisplayFlags },
     {"nativeSetDisplayProjection", "(JLandroid/os/IBinder;IIIIIIIII)V",
             (void*)nativeSetDisplayProjection },
     {"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V",
diff --git a/core/proto/android/server/OWNERS b/core/proto/android/server/OWNERS
new file mode 100644
index 0000000..72d39bf
--- /dev/null
+++ b/core/proto/android/server/OWNERS
@@ -0,0 +1 @@
+per-file window*.proto = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/proto/android/server/accessibilitytrace.proto b/core/proto/android/server/accessibilitytrace.proto
index 1fc4a01..41fecfd 100644
--- a/core/proto/android/server/accessibilitytrace.proto
+++ b/core/proto/android/server/accessibilitytrace.proto
@@ -46,17 +46,17 @@
     /* required: elapsed realtime in nanos since boot of when this entry was logged */
     optional fixed64 elapsed_realtime_nanos = 1;
     optional string calendar_time = 2;
-
-    optional string process_name = 3;
-    optional string thread_id_name = 4;
+    repeated string logging_type = 3;
+    optional string process_name = 4;
+    optional string thread_id_name = 5;
 
     /* where the trace originated */
-    optional string where = 5;
+    optional string where = 6;
 
-    optional string calling_pkg = 6;
-    optional string calling_params = 7;
-    optional string calling_stacks = 8;
+    optional string calling_pkg = 7;
+    optional string calling_params = 8;
+    optional string calling_stacks = 9;
 
-    optional AccessibilityDumpProto accessibility_service = 9;
-    optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 10;
+    optional AccessibilityDumpProto accessibility_service = 10;
+    optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 11;
 }
diff --git a/core/proto/android/server/inputmethod/OWNERS b/core/proto/android/server/inputmethod/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/core/proto/android/server/inputmethod/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index fa1e9d4..0121bff 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -278,7 +278,7 @@
 message TaskProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional WindowContainerProto window_container = 1;
+    optional WindowContainerProto window_container = 1 [deprecated=true];
     optional int32 id = 2;
     reserved 3; // activity
     optional bool fills_parent = 4;
@@ -295,12 +295,12 @@
     optional string real_activity = 13;
     optional string orig_activity = 14;
 
-    optional int32 display_id = 15;
+    optional int32 display_id = 15 [deprecated=true];
     optional int32 root_task_id = 16;
-    optional int32 activity_type = 17 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"];
+    optional int32 activity_type = 17 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType", deprecated=true] ;
     optional int32 resize_mode = 18 [(.android.typedef) = "android.appwidget.AppWidgetProviderInfo.ResizeModeFlags"];
-    optional int32 min_width = 19;
-    optional int32 min_height = 20;
+    optional int32 min_width = 19 [deprecated=true];
+    optional int32 min_height = 20 [deprecated=true];
 
     optional .android.graphics.RectProto adjusted_bounds = 21;
     optional .android.graphics.RectProto last_non_fullscreen_bounds = 22;
@@ -312,6 +312,18 @@
     optional bool created_by_organizer = 28;
     optional string affinity = 29;
     optional bool has_child_pip_activity = 30;
+    optional TaskFragmentProto task_fragment = 31;
+}
+
+/* represents TaskFragment */
+message TaskFragmentProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional WindowContainerProto window_container = 1;
+    optional int32 display_id = 2;
+    optional int32 activity_type = 3 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"];
+    optional int32 min_width = 4;
+    optional int32 min_height = 5;
 }
 
 /* represents ActivityRecordProto */
@@ -493,6 +505,8 @@
     optional WindowTokenProto window_token = 7;
     /* represents a WindowState child */
     optional WindowStateProto window = 8;
+    /* represents a WindowState child */
+    optional TaskFragmentProto task_fragment = 9;
 }
 
 /* represents ConfigurationContainer */
diff --git a/core/proto/android/view/OWNERS b/core/proto/android/view/OWNERS
new file mode 100644
index 0000000..d72a0f0
--- /dev/null
+++ b/core/proto/android/view/OWNERS
@@ -0,0 +1,3 @@
+include /services/core/java/com/android/server/wm/OWNERS
+
+per-file ime*.proto = file:/core/java/android/view/inputmethod/OWNERS
diff --git a/core/proto/android/view/inputmethod/OWNERS b/core/proto/android/view/inputmethod/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/core/proto/android/view/inputmethod/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 64b8a1a..4350a82 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -202,6 +202,8 @@
     <protected-broadcast
         android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" />
     <protected-broadcast
+        android:name="android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED" />
+    <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
@@ -2590,7 +2592,7 @@
          third-party apps.
     -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
-        android:protectionLevel="signature|documenter" />
+        android:protectionLevel="signature|role" />
 
     <!-- Allows an application to manage access to crates, usually as part
          of a crates picker.
@@ -2607,7 +2609,7 @@
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.CACHE_CONTENT"
-        android:protectionLevel="signature|documenter" />
+        android:protectionLevel="signature|role" />
 
     <!-- @SystemApi @hide
          Allows an application to aggressively allocate disk space.
@@ -2753,7 +2755,7 @@
 
     <!-- @SystemApi @TestApi @hide Allows an application to change to remove/kill tasks -->
     <permission android:name="android.permission.REMOVE_TASKS"
-        android:protectionLevel="signature|documenter|recents" />
+        android:protectionLevel="signature|recents|role" />
 
     <!-- @deprecated Use MANAGE_ACTIVITY_TASKS instead.
          @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 614779a..c6983ae 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -93,7 +93,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginEnd="@dimen/notification_header_separating_margin"
-                    android:ellipsize="marquee"
+                    android:ellipsize="end"
                     android:fadingEdge="horizontal"
                     android:singleLine="true"
                     android:textAlignment="viewStart"
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 2991b17..95ddc2e 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -93,7 +93,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginEnd="@dimen/notification_header_separating_margin"
-                    android:ellipsize="marquee"
+                    android:ellipsize="end"
                     android:fadingEdge="horizontal"
                     android:singleLine="true"
                     android:textAlignment="viewStart"
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index 3564f97..bef1d0b 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -119,7 +119,7 @@
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_marginEnd="@dimen/notification_header_separating_margin"
-                            android:ellipsize="marquee"
+                            android:ellipsize="end"
                             android:fadingEdge="horizontal"
                             android:singleLine="true"
                             android:textAlignment="viewStart"
diff --git a/core/res/res/layout/notification_template_text.xml b/core/res/res/layout/notification_template_text.xml
index 4920c79..7b834a4 100644
--- a/core/res/res/layout/notification_template_text.xml
+++ b/core/res/res/layout/notification_template_text.xml
@@ -21,7 +21,7 @@
     android:layout_height="@dimen/notification_text_height"
     android:layout_gravity="top"
     android:layout_marginTop="@dimen/notification_text_margin_top"
-    android:ellipsize="marquee"
+    android:ellipsize="end"
     android:fadingEdge="horizontal"
     android:gravity="top"
     android:singleLine="true"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 8af85dd..39f52d8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nie gemerk nie"</string>
     <string name="selected" msgid="6614607926197755875">"gekies"</string>
     <string name="not_selected" msgid="410652016565864475">"nie gekies nie"</string>
+    <string name="in_progress" msgid="2149208189184319441">"aan die gang"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Voltooi handeling met"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Voltooi handeling met gebruik van %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Voltooi handeling"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index d1c7c49..c9df0e0 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ምልክት አልተደረገበትም"</string>
     <string name="selected" msgid="6614607926197755875">"ተመርጧል"</string>
     <string name="not_selected" msgid="410652016565864475">"አልተመረጠም"</string>
+    <string name="in_progress" msgid="2149208189184319441">"በሂደት ላይ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"... በመጠቀም ድርጊቱን አጠናቅ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sን ተጠቅመው እርምጃ ያጠናቅቁ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"እርምጃውን አጠናቅቅ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 39e3021..cb64b33 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1267,6 +1267,7 @@
     <string name="not_checked" msgid="7972320087569023342">"لم يتم وضع علامة"</string>
     <string name="selected" msgid="6614607926197755875">"محدّد"</string>
     <string name="not_selected" msgid="410652016565864475">"غير محدّد"</string>
+    <string name="in_progress" msgid="2149208189184319441">"قيد التقدّم"</string>
     <string name="whichApplication" msgid="5432266899591255759">"إكمال الإجراء باستخدام"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏إكمال الإجراء باستخدام %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"إكمال الإجراء"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index ad3d746..ba0398a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1189,6 +1189,7 @@
     <string name="not_checked" msgid="7972320087569023342">"টিক চিহ্ন দিয়া হোৱা নাই"</string>
     <string name="selected" msgid="6614607926197755875">"বাছনি কৰা"</string>
     <string name="not_selected" msgid="410652016565864475">"বাছনি কৰা হোৱা নাই"</string>
+    <string name="in_progress" msgid="2149208189184319441">"চলি আছে"</string>
     <string name="whichApplication" msgid="5432266899591255759">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যৱহাৰ কৰি কাৰ্যটো সম্পূৰ্ণ কৰক"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"কাৰ্য সম্পূৰ্ণ কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 85f1b47..fe1ea98 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"yoxlanılmayıb"</string>
     <string name="selected" msgid="6614607926197755875">"seçilib"</string>
     <string name="not_selected" msgid="410652016565864475">"seçilməyib"</string>
+    <string name="in_progress" msgid="2149208189184319441">"davam edir"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Əməliyyatı tamamlayın:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s istifadə edərək əməliyyatı tamamlayın"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Əməliyyatı tamamlayın"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index a763cf3..c2c8a5e 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1203,6 +1203,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
     <string name="selected" msgid="6614607926197755875">"izabrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nije izabrano"</string>
+    <string name="in_progress" msgid="2149208189184319441">"u toku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dovrši radnju preko"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Završi radnju"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 003b5e5..e948cbe 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1227,6 +1227,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не пазначана"</string>
     <string name="selected" msgid="6614607926197755875">"выбраны"</string>
     <string name="not_selected" msgid="410652016565864475">"не выбраны"</string>
+    <string name="in_progress" msgid="2149208189184319441">"выконваецца"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Завяршыць дзеянне з дапамогай"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завяршыць дзеянне з дапамогай %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Завяршыць дзеянне"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b72e780..ab73ebc 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"без отметка"</string>
     <string name="selected" msgid="6614607926197755875">"избрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не е избрано"</string>
+    <string name="in_progress" msgid="2149208189184319441">"в ход"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Изпълняване на действието чрез"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завършване на действието посредством %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Изпълняване на действието"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 718eef0..3c3ce59 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"টিকচিহ্ন দেওয়া নেই"</string>
     <string name="selected" msgid="6614607926197755875">"বেছে নেওয়া হয়েছে"</string>
     <string name="not_selected" msgid="410652016565864475">"বেছে নেওয়া হয়নি"</string>
+    <string name="in_progress" msgid="2149208189184319441">"কাজ চলছে"</string>
     <string name="whichApplication" msgid="5432266899591255759">"এটি ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 59d03d9..1ee5c34 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1203,6 +1203,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
     <string name="selected" msgid="6614607926197755875">"odabrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nije odabrano"</string>
+    <string name="in_progress" msgid="2149208189184319441">"u toku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Završite radnju pomoću aplikacije"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvršiti akciju"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e06cc37..6da0249 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"no seleccionat"</string>
     <string name="selected" msgid="6614607926197755875">"seleccionat"</string>
     <string name="not_selected" msgid="410652016565864475">"no seleccionat"</string>
+    <string name="in_progress" msgid="2149208189184319441">"en curs"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completa l\'acció mitjançant"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completa l\'acció amb %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completa l\'acció"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 1ec443e..2e28787 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nevybráno"</string>
     <string name="selected" msgid="6614607926197755875">"vybráno"</string>
     <string name="not_selected" msgid="410652016565864475">"nevybráno"</string>
+    <string name="in_progress" msgid="2149208189184319441">"probíhá"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončit akci pomocí aplikace"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončit akci pomocí aplikace %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončit akci"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e0bfb59..6f04a14 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"slået fra"</string>
     <string name="selected" msgid="6614607926197755875">"valgt"</string>
     <string name="not_selected" msgid="410652016565864475">"ikke valgt"</string>
+    <string name="in_progress" msgid="2149208189184319441">"i gang"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Brug"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Gennemfør handling ved hjælp af %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Afslut handling"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5af538d..6b5074c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"deaktiviert"</string>
     <string name="selected" msgid="6614607926197755875">"ausgewählt"</string>
     <string name="not_selected" msgid="410652016565864475">"nicht ausgewählt"</string>
+    <string name="in_progress" msgid="2149208189184319441">"Noch nicht abgeschlossen"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Aktion durchführen mit"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Aktion mit %1$s abschließen"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Abschließen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 3f14d04..c08791d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"μη επιλεγμένο"</string>
     <string name="selected" msgid="6614607926197755875">"επιλεγμένο"</string>
     <string name="not_selected" msgid="410652016565864475">"μη επιλεγμένο"</string>
+    <string name="in_progress" msgid="2149208189184319441">"σε εξέλιξη"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Ολοκληρωμένη ενέργεια με χρήση %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Ολοκλήρωση ενέργειας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 253de2c..da28d71 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
+    <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 10e6831..ad18acf 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not checked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
+    <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7aea9a7..24279a19 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
+    <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 257f403..7d45c91 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
+    <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index df52af8..7458e8b 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎not checked‎‏‎‎‏‎"</string>
     <string name="selected" msgid="6614607926197755875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎selected‎‏‎‎‏‎"</string>
     <string name="not_selected" msgid="410652016565864475">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎not selected‎‏‎‎‏‎"</string>
+    <string name="in_progress" msgid="2149208189184319441">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎in progress‎‏‎‎‏‎"</string>
     <string name="whichApplication" msgid="5432266899591255759">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎Complete action using‎‏‎‎‏‎"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎Complete action using %1$s‎‏‎‎‏‎"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎Complete action‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5cc92a0..6a23351 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"desactivado"</string>
     <string name="selected" msgid="6614607926197755875">"seleccionado"</string>
     <string name="not_selected" msgid="410652016565864475">"no seleccionado"</string>
+    <string name="in_progress" msgid="2149208189184319441">"en curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar la acción mediante"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1d7c4a3..6d39a2c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"no seleccionado"</string>
     <string name="selected" msgid="6614607926197755875">"seleccionado"</string>
     <string name="not_selected" msgid="410652016565864475">"no seleccionado"</string>
+    <string name="in_progress" msgid="2149208189184319441">"en curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar acción utilizando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cbcee59..ddb38f4 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"märkimata"</string>
     <string name="selected" msgid="6614607926197755875">"valitud"</string>
     <string name="not_selected" msgid="410652016565864475">"pole valitud"</string>
+    <string name="in_progress" msgid="2149208189184319441">"pooleli"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Lõpetage toiming rakendusega"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Toimingu lõpetamine, kasutades rakendust %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Vii toiming lõpule"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index c3172a6..5c6219d 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"markatu gabe"</string>
     <string name="selected" msgid="6614607926197755875">"hautatuta"</string>
     <string name="not_selected" msgid="410652016565864475">"hautatu gabe"</string>
+    <string name="in_progress" msgid="2149208189184319441">"abian"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Gauzatu ekintza hau erabilita:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Osatu ekintza %1$s erabiliz"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Osatu ekintza"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 4105e266..4e75e21 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"بدون علامت"</string>
     <string name="selected" msgid="6614607926197755875">"انتخاب شده"</string>
     <string name="not_selected" msgid="410652016565864475">"انتخاب نشده"</string>
+    <string name="in_progress" msgid="2149208189184319441">"درحال انجام"</string>
     <string name="whichApplication" msgid="5432266899591255759">"تکمیل کنش بااستفاده از"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏تکمیل کنش بااستفاده از %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"تکمیل عملکرد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f5bc75b..cdca717 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ei valittu"</string>
     <string name="selected" msgid="6614607926197755875">"valittu"</string>
     <string name="not_selected" msgid="410652016565864475">"ei valittu"</string>
+    <string name="in_progress" msgid="2149208189184319441">"käynnissä"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Tee toiminto käyttäen sovellusta"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Suorita sovelluksella %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Suorita toiminto"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index cbf8d69..4fb5b4b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"non coché"</string>
     <string name="selected" msgid="6614607926197755875">"sélectionné"</string>
     <string name="not_selected" msgid="410652016565864475">"non sélectionné"</string>
+    <string name="in_progress" msgid="2149208189184319441">"en cours"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Continuer avec %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 69daf30..e10a719 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"désactivé"</string>
     <string name="selected" msgid="6614607926197755875">"sélectionné"</string>
     <string name="not_selected" msgid="410652016565864475">"non sélectionné"</string>
+    <string name="in_progress" msgid="2149208189184319441">"en cours"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Terminer l\'action avec %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 157f01f..d20e77f 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"non seleccionado"</string>
     <string name="selected" msgid="6614607926197755875">"elemento seleccionado"</string>
     <string name="not_selected" msgid="410652016565864475">"elemento non seleccionado"</string>
+    <string name="in_progress" msgid="2149208189184319441">"en curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar a acción usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar a acción usando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 6dcb8ef..915cfe1 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1189,6 +1189,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ચેક કર્યું નથી"</string>
     <string name="selected" msgid="6614607926197755875">"પસંદ કરેલી"</string>
     <string name="not_selected" msgid="410652016565864475">"પસંદ નહીં કરેલી"</string>
+    <string name="in_progress" msgid="2149208189184319441">"પ્રક્રિયા ચાલુ છે"</string>
     <string name="whichApplication" msgid="5432266899591255759">"આના ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ક્રિયા પૂર્ણ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 9a205dd..27db7eb 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"बंद है"</string>
     <string name="selected" msgid="6614607926197755875">"चुना गया"</string>
     <string name="not_selected" msgid="410652016565864475">"नहीं चुना गया"</string>
+    <string name="in_progress" msgid="2149208189184319441">"जारी है"</string>
     <string name="whichApplication" msgid="5432266899591255759">"इसका इस्तेमाल करके कार्रवाई को पूरा करें"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s का उपयोग करके कार्रवाई पूरी करें"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"कार्रवाई पूरी करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 06812bb0..d804f09 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1203,6 +1203,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nije potvrđeno"</string>
     <string name="selected" msgid="6614607926197755875">"odabrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nije odabrano"</string>
+    <string name="in_progress" msgid="2149208189184319441">"u tijeku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Radnju dovrši pomoću stavke"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršavanje radnje pomoću aplikacije %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Dovrši radnju"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 1a4723c..44d8e9b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nincs kiválasztva"</string>
     <string name="selected" msgid="6614607926197755875">"kiválasztva"</string>
     <string name="not_selected" msgid="410652016565864475">"nincs kiválasztva"</string>
+    <string name="in_progress" msgid="2149208189184319441">"folyamatban"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Művelet végrehajtása a következővel:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Művelet elvégzése a(z) %1$s segítségével"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Művelet végrehajtása"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 211050b..847ed3e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"նշված չէ"</string>
     <string name="selected" msgid="6614607926197755875">"ընտրված է"</string>
     <string name="not_selected" msgid="410652016565864475">"ընտրված չէ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ընթացքում է"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ավարտել գործողությունը` օգտագործելով"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Եզրափակել գործողությունը՝ օգտագործելով %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Ավարտել գործողությունը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4e6ee68..c4f8fdd 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -602,8 +602,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string>
-    <!-- no translation found for fingerprint_error_bad_calibration (4385512597740168120) -->
-    <skip />
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Tidak dapat menggunakan sensor sidik jari. Kunjungi penyedia reparasi"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan sidik jari"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan sidik jari atau kunci layar"</string>
@@ -619,12 +618,9 @@
     <string name="face_setup_notification_content" msgid="5463999831057751676">"Buka kunci ponsel dengan melihat ke ponsel"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Siapkan lebih banyak cara untuk membuka kunci"</string>
     <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Ketuk untuk menambahkan sidik jari"</string>
-    <!-- no translation found for fingerprint_recalibrate_notification_name (1414578431898579354) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_title (2406561052064558497) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_content (8519935717822194943) -->
-    <skip />
+    <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string>
+    <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Tidak dapat menggunakan sensor sidik jari"</string>
+    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Kunjungi penyedia reparasi."</string>
     <string name="face_acquired_insufficient" msgid="2150805835949162453">"Tidak bisa mengambil data wajah akurat. Coba lagi."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Coba cahaya yang lebih lembut."</string>
     <string name="face_acquired_too_dark" msgid="252573548464426546">"Terlalu gelap. Coba pencahayaan yang lebih cerah."</string>
@@ -1187,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"tidak dicentang"</string>
     <string name="selected" msgid="6614607926197755875">"dipilih"</string>
     <string name="not_selected" msgid="410652016565864475">"tidak dipilih"</string>
+    <string name="in_progress" msgid="2149208189184319441">"dalam proses"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 1f5559f..dfe3acb 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ekki valið"</string>
     <string name="selected" msgid="6614607926197755875">"valið"</string>
     <string name="not_selected" msgid="410652016565864475">"ekki valið"</string>
+    <string name="in_progress" msgid="2149208189184319441">"í gangi"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ljúka aðgerð með"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Ljúka aðgerð með %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Ljúka aðgerð"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 798acc0..1e204cf 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"deselezionato"</string>
     <string name="selected" msgid="6614607926197755875">"selezionato"</string>
     <string name="not_selected" msgid="410652016565864475">"non selezionato"</string>
+    <string name="in_progress" msgid="2149208189184319441">"In corso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completa l\'azione con"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completamento azione con %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completa azione"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5aacfa7..d764cb7 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1227,6 +1227,7 @@
     <string name="not_checked" msgid="7972320087569023342">"לא מסומן"</string>
     <string name="selected" msgid="6614607926197755875">"נבחר"</string>
     <string name="not_selected" msgid="410652016565864475">"לא נבחר"</string>
+    <string name="in_progress" msgid="2149208189184319441">"בתהליך"</string>
     <string name="whichApplication" msgid="5432266899591255759">"השלמת הפעולה באמצעות"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏השלמת הפעולה באמצעות %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"להשלמת הפעולה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 609c5a9..bc0e43d 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"OFF"</string>
     <string name="selected" msgid="6614607926197755875">"選択済み"</string>
     <string name="not_selected" msgid="410652016565864475">"未選択"</string>
+    <string name="in_progress" msgid="2149208189184319441">"進行中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"アプリケーションを選択"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sを使用してアクションを完了"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"アクションを実行"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 8a68fb9..8492476 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"არ არის მონიშნული"</string>
     <string name="selected" msgid="6614607926197755875">"არჩეულია"</string>
     <string name="not_selected" msgid="410652016565864475">"არ არის არჩეული"</string>
+    <string name="in_progress" msgid="2149208189184319441">"მიმდინარეობს"</string>
     <string name="whichApplication" msgid="5432266899591255759">"რა გამოვიყენოთ?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"მოქმედების %1$s-ის გამოყენებით დასრულება"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"მოქმედების დასრულება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index df6a2aa..399b927 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"белгіленбеген"</string>
     <string name="selected" msgid="6614607926197755875">"таңдалған"</string>
     <string name="not_selected" msgid="410652016565864475">"таңдалмаған"</string>
+    <string name="in_progress" msgid="2149208189184319441">"орындалуда"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Әрекетті аяқтау"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Әрекетті %1$s қолданбасын пайдаланып аяқтау"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Әрекетті аяқтау"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index edbd547..a4f0c00 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"មិន​បាន​ធីក​"</string>
     <string name="selected" msgid="6614607926197755875">"បាន​ជ្រើសរើស"</string>
     <string name="not_selected" msgid="410652016565864475">"មិនបានជ្រើសរើសទេ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"កំពុងដំណើរការ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ​ %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"បញ្ចប់សកម្មភាព"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 17b550db..4578a9e 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="selected" msgid="6614607926197755875">"ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
     <string name="not_selected" msgid="410652016565864475">"ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 9df09b4..4494fe5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"선택 안함"</string>
     <string name="selected" msgid="6614607926197755875">"선택됨"</string>
     <string name="not_selected" msgid="410652016565864475">"선택되지 않음"</string>
+    <string name="in_progress" msgid="2149208189184319441">"진행 중"</string>
     <string name="whichApplication" msgid="5432266899591255759">"작업을 수행할 때 사용하는 애플리케이션"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s을(를) 사용하여 작업 완료"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"작업 완료"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 820a79c..cc1bd2c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"белгилене элек"</string>
     <string name="selected" msgid="6614607926197755875">"тандалган"</string>
     <string name="not_selected" msgid="410652016565864475">"тандалган жок"</string>
+    <string name="in_progress" msgid="2149208189184319441">"аткарылууда"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Кайсынысын колдоносуз?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s аркылуу аракетти аягына чейин чыгаруу"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Аракетти аягына чыгаруу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 982845c..02c41aa 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ບໍ່ໄດ້ໝາຍຖືກ"</string>
     <string name="selected" msgid="6614607926197755875">"ເລືອກແລ້ວ"</string>
     <string name="not_selected" msgid="410652016565864475">"ບໍ່ໄດ້ເລືອກແລ້ວ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ກຳລັງດຳເນີນການ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ດຳເນີນການໂດຍໃຊ້"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"ສຳ​ເລັດ​​​ການ​ດຳ​ເນີນ​ການ​ໂດຍ​ໃຊ້ %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ສຳເລັດຄຳສັ່ງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c76c811..0a644b1 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nepažymėta"</string>
     <string name="selected" msgid="6614607926197755875">"pasirinkta"</string>
     <string name="not_selected" msgid="410652016565864475">"nepasirinkta"</string>
+    <string name="in_progress" msgid="2149208189184319441">"vykdoma"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Užbaigti veiksmą naudojant"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Užbaigti veiksmą naudojant %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Užbaigti veiksmą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a00523c..1647e3c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string>
-    <!-- no translation found for fingerprint_error_bad_calibration (4385512597740168120) -->
-    <skip />
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Nevar izmantot pirksta nospieduma sensoru. Sazinieties ar remonta pakalpojumu sniedzēju."</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Pirksta nospieduma izmantošana"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Pirksta nospieduma vai ekrāna bloķēšanas metodes izmantošana"</string>
@@ -622,12 +621,9 @@
     <string name="face_setup_notification_content" msgid="5463999831057751676">"Atbloķējiet tālruni, skatoties uz to"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Citi atbloķēšanas veidi"</string>
     <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Pieskarieties, lai pievienotu pirksta nospiedumu"</string>
-    <!-- no translation found for fingerprint_recalibrate_notification_name (1414578431898579354) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_title (2406561052064558497) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_content (8519935717822194943) -->
-    <skip />
+    <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Autorizācija ar pirksta nospiedumu"</string>
+    <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nevar izmantot pirksta nospieduma sensoru"</string>
+    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Sazinieties ar remonta pakalpojumu sniedzēju."</string>
     <string name="face_acquired_insufficient" msgid="2150805835949162453">"Neizdevās tvert sejas datus. Mēģiniet vēlreiz."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Pārāk spilgts. Izmēģiniet maigāku apgaismojumu."</string>
     <string name="face_acquired_too_dark" msgid="252573548464426546">"Pārāk tumšs. Izmēģiniet spožāku apgaismojumu."</string>
@@ -1207,6 +1203,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nav atzīmēts"</string>
     <string name="selected" msgid="6614607926197755875">"atlasīts"</string>
     <string name="not_selected" msgid="410652016565864475">"nav atlasīts"</string>
+    <string name="in_progress" msgid="2149208189184319441">"notiek apstrāde"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Izvēlieties lietotni"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Pabeigt darbību, izmantojot %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Pabeigt darbību"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index fbda7b4..df9c644 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не е штиклирано"</string>
     <string name="selected" msgid="6614607926197755875">"избрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не е избрано"</string>
+    <string name="in_progress" msgid="2149208189184319441">"во тек"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Активирај со"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Остварете го дејството со %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши го дејството"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 2274cda..c6b26a5 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"പരിശോധിക്കാത്തത്"</string>
     <string name="selected" msgid="6614607926197755875">"തിരഞ്ഞെടുത്തു"</string>
     <string name="not_selected" msgid="410652016565864475">"തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
+    <string name="in_progress" msgid="2149208189184319441">"പുരോഗതിയിലാണ്"</string>
     <string name="whichApplication" msgid="5432266899591255759">"പൂർണ്ണമായ പ്രവർത്തനം ഉപയോഗിക്കുന്നു"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ഉപയോഗിച്ച് പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 3936541..06b6717 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"тэмдэглээгүй"</string>
     <string name="selected" msgid="6614607926197755875">"сонгосон"</string>
     <string name="not_selected" msgid="410652016565864475">"сонгоогүй"</string>
+    <string name="in_progress" msgid="2149208189184319441">"үргэлжилж байна"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Үйлдлийг дуусгах"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ашиглан үйлдлийг гүйцээх"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Үйлдлийг дуусгах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 1d2f96a..312cb3f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"तपासले नाही"</string>
     <string name="selected" msgid="6614607926197755875">"निवडला"</string>
     <string name="not_selected" msgid="410652016565864475">"निवडला नाही"</string>
+    <string name="in_progress" msgid="2149208189184319441">"प्रगतीपथावर आहे"</string>
     <string name="whichApplication" msgid="5432266899591255759">"याचा वापर करून क्रिया पूर्ण करा"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s वापरून क्रिया पूर्ण करा"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"क्रिया पूर्ण झाली"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 095c3d3..28da92e 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"tidak ditandai"</string>
     <string name="selected" msgid="6614607926197755875">"dipilih"</string>
     <string name="not_selected" msgid="410652016565864475">"tidak dipilih"</string>
+    <string name="in_progress" msgid="2149208189184319441">"dalam proses"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index f0b5b0f..fbf4ff5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -602,8 +602,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
-    <!-- no translation found for fingerprint_error_bad_calibration (4385512597740168120) -->
-    <skip />
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"လက်ဗွေ အာရုံခံကိရိယာကို အသုံးပြု၍ မရပါ။ ပြုပြင်ရေး ဝန်ဆောင်မှုပေးသူထံသို့ သွားပါ"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"လက်ဗွေ သုံးခြင်း"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string>
@@ -619,12 +618,9 @@
     <string name="face_setup_notification_content" msgid="5463999831057751676">"သင့်ဖုန်းကိုကြည့်၍ သော့ဖွင့်ပါ"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"သော့ဖွင့်ရန် နောက်ထပ်နည်းလမ်းများကို စနစ်ထည့်သွင်းပါ"</string>
     <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"လက်ဗွေထည့်ရန် တို့ပါ"</string>
-    <!-- no translation found for fingerprint_recalibrate_notification_name (1414578431898579354) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_title (2406561052064558497) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_content (8519935717822194943) -->
-    <skip />
+    <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"လက်ဗွေသုံး လော့ခ်ဖွင့်ခြင်း"</string>
+    <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"လက်ဗွေ အာရုံခံကိရိယာကို အသုံးပြု၍ မရပါ"</string>
+    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ပြုပြင်ရေး ဝန်ဆောင်မှုပေးသူထံသို့ သွားပါ။"</string>
     <string name="face_acquired_insufficient" msgid="2150805835949162453">"မျက်နှာဒေတာ အမှန် မရိုက်ယူနိုင်ပါ၊ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"အလွန် လင်းသည်။ အလင်းလျှော့ကြည့်ပါ။"</string>
     <string name="face_acquired_too_dark" msgid="252573548464426546">"အလွန်မှောင်သည်။ ပိုလင်းအောင် လုပ်ကြည့်ပါ။"</string>
@@ -1187,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ခြစ် မထား"</string>
     <string name="selected" msgid="6614607926197755875">"ရွေးချယ်ထားသည်"</string>
     <string name="not_selected" msgid="410652016565864475">"ရွေးချယ်မထားပါ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ဆောင်ရွက်နေသည်"</string>
     <string name="whichApplication" msgid="5432266899591255759">"အောက်ပါတို့ကို အသုံးပြုမှု အပြီးသတ်ခြင်း"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ကို သုံးပြီး လုပ်ဆောင်ချက် ပြီးဆုံးပါစေ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"လုပ်ဆောင်ချက်ကို အပြီးသတ်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c71b690..d530ffe 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ikke avmerket"</string>
     <string name="selected" msgid="6614607926197755875">"valgt"</string>
     <string name="not_selected" msgid="410652016565864475">"ikke valgt"</string>
+    <string name="in_progress" msgid="2149208189184319441">"pågår"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Fullfør med"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Fullfør handlingen med %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Fullfør handlingen"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 929d032..834aec2 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1189,6 +1189,7 @@
     <string name="not_checked" msgid="7972320087569023342">"जाँच गरिएको छैन"</string>
     <string name="selected" msgid="6614607926197755875">"चयन गरियो"</string>
     <string name="not_selected" msgid="410652016565864475">"चयन गरिएन"</string>
+    <string name="in_progress" msgid="2149208189184319441">"जारी छ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"निम्न एपको प्रयोग गरी कारबाही पुरा गर्नुहोस्: %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"पूर्ण कारबाही"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7401212..c63f6f8 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"niet aangevinkt"</string>
     <string name="selected" msgid="6614607926197755875">"geselecteerd"</string>
     <string name="not_selected" msgid="410652016565864475">"niet geselecteerd"</string>
+    <string name="in_progress" msgid="2149208189184319441">"bezig"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Actie voltooien met"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Actie voltooien via %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Actie voltooien"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 7885f67..06d9dcd 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string>
     <string name="selected" msgid="6614607926197755875">"ଚୟନ କରାଯାଇଛି"</string>
     <string name="not_selected" msgid="410652016565864475">"ଚୟନ କରାଯାଇନାହିଁ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ଚାଲୁଅଛି"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index f5f8a55..a962bc3 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1189,6 +1189,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ਨਿਸ਼ਾਨਬੱਧ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="selected" msgid="6614607926197755875">"ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="not_selected" msgid="410652016565864475">"ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ਜਾਰੀ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ਇਸਨੂੰ ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8e0f2b4..769b28b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nie wybrano"</string>
     <string name="selected" msgid="6614607926197755875">"wybrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nie wybrano"</string>
+    <string name="in_progress" msgid="2149208189184319441">"w toku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Wykonaj czynność przez..."</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Wykonaj czynność w aplikacji %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Wykonaj działanie"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f0be5ec..04fae07 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
     <string name="selected" msgid="6614607926197755875">"selecionado"</string>
     <string name="not_selected" msgid="410652016565864475">"não selecionado"</string>
+    <string name="in_progress" msgid="2149208189184319441">"em andamento"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index d721932..3e32496 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"não selecionado"</string>
     <string name="selected" msgid="6614607926197755875">"selecionado"</string>
     <string name="not_selected" msgid="410652016565864475">"não selecionado"</string>
+    <string name="in_progress" msgid="2149208189184319441">"em curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Concluir ação utilizando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir ação utilizando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f0be5ec..04fae07 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
     <string name="selected" msgid="6614607926197755875">"selecionado"</string>
     <string name="not_selected" msgid="410652016565864475">"não selecionado"</string>
+    <string name="in_progress" msgid="2149208189184319441">"em andamento"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5a37821..718203b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1207,6 +1207,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nebifat"</string>
     <string name="selected" msgid="6614607926197755875">"selectat"</string>
     <string name="not_selected" msgid="410652016565864475">"neselectat"</string>
+    <string name="in_progress" msgid="2149208189184319441">"în curs"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Finalizare acțiune utilizând"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Finalizați acțiunea utilizând %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Finalizați acțiunea"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6820452..fe81df7 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string>
     <string name="selected" msgid="6614607926197755875">"выбрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не выбрано"</string>
+    <string name="in_progress" msgid="2149208189184319441">"в процессе"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Что использовать?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Выполнить с помощью приложения \"%1$s\""</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Выполнить действие"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index d17dd44..f7b709d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"පරීක්ෂා කර නැත"</string>
     <string name="selected" msgid="6614607926197755875">"තෝරන ලදි"</string>
     <string name="not_selected" msgid="410652016565864475">"තෝරා නොමැත"</string>
+    <string name="in_progress" msgid="2149208189184319441">"සිදු වෙමින් පවතී"</string>
     <string name="whichApplication" msgid="5432266899591255759">"පහත භාවිතයෙන් ක්‍රියාව සම්පූර්ණ කරන්න"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s භාවිතා කරමින් ක්‍රියාව සම්පුර්ණ කරන්න"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ක්‍රියාව සම්පූර්ණ කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f44c8d8..abe06b1 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nezačiarknuté"</string>
     <string name="selected" msgid="6614607926197755875">"vybrané"</string>
     <string name="not_selected" msgid="410652016565864475">"nevybrané"</string>
+    <string name="in_progress" msgid="2149208189184319441">"prebieha"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončiť akciu pomocou aplikácie"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončiť akciu pomocou aplikácie %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončiť akciu"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 0f79fb6..a329a45 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ni potrjeno"</string>
     <string name="selected" msgid="6614607926197755875">"izbrano"</string>
     <string name="not_selected" msgid="410652016565864475">"ni izbrano"</string>
+    <string name="in_progress" msgid="2149208189184319441">"v teku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z aplikacijo"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončanje dejanja z aplikacijo %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvedba dejanja"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 57c1297..13ec43e 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nuk u përzgjodh"</string>
     <string name="selected" msgid="6614607926197755875">"i zgjedhur"</string>
     <string name="not_selected" msgid="410652016565864475">"i pazgjedhur"</string>
+    <string name="in_progress" msgid="2149208189184319441">"në vazhdim"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Përfundo veprimin duke përdorur"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Përfundo veprimin duke përdorur %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Përfundo veprimin"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8c7c5fe..b3170a4 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1203,6 +1203,7 @@
     <string name="not_checked" msgid="7972320087569023342">"није означено"</string>
     <string name="selected" msgid="6614607926197755875">"изабрано"</string>
     <string name="not_selected" msgid="410652016565864475">"није изабрано"</string>
+    <string name="in_progress" msgid="2149208189184319441">"у току"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Доврши радњу преко"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завршите радњу помоћу апликације %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши радњу"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b45a94a..ea0e9d6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"inte markerad"</string>
     <string name="selected" msgid="6614607926197755875">"valt"</string>
     <string name="not_selected" msgid="410652016565864475">"inte valt"</string>
+    <string name="in_progress" msgid="2149208189184319441">"pågår"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Slutför åtgärd genom att använda"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Slutför åtgärden med %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Slutför åtgärd"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 163ad53..98c9b07 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"haijateuliwa"</string>
     <string name="selected" msgid="6614607926197755875">"imechaguliwa"</string>
     <string name="not_selected" msgid="410652016565864475">"haijachaguliwa"</string>
+    <string name="in_progress" msgid="2149208189184319441">"inaendelea"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Kamilisha kitendo ukitumia"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Kamilisha kitendo ukitumia %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Kamilisha kitendo"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 26fa15b..ffc54b9 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"முடக்கப்பட்டுள்ளது"</string>
     <string name="selected" msgid="6614607926197755875">"தேர்ந்தெடுக்கப்பட்டது"</string>
     <string name="not_selected" msgid="410652016565864475">"தேர்ந்தெடுக்கப்படவில்லை"</string>
+    <string name="in_progress" msgid="2149208189184319441">"செயலிலுள்ளது"</string>
     <string name="whichApplication" msgid="5432266899591255759">"இதைப் பயன்படுத்தி செயலை நிறைவுசெய்"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ஐப் பயன்படுத்தி செயலை முடிக்கவும்"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"செயலை முடி"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6c92268..acb1157 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ఎంచుకోలేదు"</string>
     <string name="selected" msgid="6614607926197755875">"ఎంచుకోబడింది"</string>
     <string name="not_selected" msgid="410652016565864475">"ఎంచుకోబడలేదు"</string>
+    <string name="in_progress" msgid="2149208189184319441">"ప్రోగ్రెస్‌లో ఉంది"</string>
     <string name="whichApplication" msgid="5432266899591255759">"దీన్ని ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sను ఉపయోగించి చర్యను పూర్తి చేయి"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"చర్యను పూర్తి చేయి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index b35ddab..137543b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ยังไม่เลือก"</string>
     <string name="selected" msgid="6614607926197755875">"เลือกไว้"</string>
     <string name="not_selected" msgid="410652016565864475">"ไม่ได้เลือกไว้"</string>
+    <string name="in_progress" msgid="2149208189184319441">"กำลังดำเนินการ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ทำงานให้เสร็จโดยใช้"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"ดำเนินการให้เสร็จสมบูรณ์โดยใช้ %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ทำงานให้เสร็จสิ้น"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 30a8042..351760c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -602,8 +602,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string>
-    <!-- no translation found for fingerprint_error_bad_calibration (4385512597740168120) -->
-    <skip />
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Hindi magamit ang sensor para sa fingerprint. Bumisita sa provider ng pag-aayos"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gumamit ng fingerprint"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gumamit ng fingerprint o lock ng screen"</string>
@@ -619,12 +618,9 @@
     <string name="face_setup_notification_content" msgid="5463999831057751676">"I-unlock ang iyong telepono sa pamamagitan ng pagtingin dito"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Mag-set up ng higit pang paraan para mag-unlock"</string>
     <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"I-tap para magdagdag ng fingerprint"</string>
-    <!-- no translation found for fingerprint_recalibrate_notification_name (1414578431898579354) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_title (2406561052064558497) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_content (8519935717822194943) -->
-    <skip />
+    <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Pag-unlock Gamit ang Fingerprint"</string>
+    <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Hindi magamit ang sensor para sa fingerprint"</string>
+    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bumisita sa provider ng pag-aayos."</string>
     <string name="face_acquired_insufficient" msgid="2150805835949162453">"Hindi makakuha ng tamang face data. Subukang muli."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Masyadong maliwanag. Subukang bawasan ang liwanag."</string>
     <string name="face_acquired_too_dark" msgid="252573548464426546">"Masyadong madilim. Subukan sa mas maliwanag."</string>
@@ -1187,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"hindi nilagyan ng check"</string>
     <string name="selected" msgid="6614607926197755875">"pinili"</string>
     <string name="not_selected" msgid="410652016565864475">"hindi pinili"</string>
+    <string name="in_progress" msgid="2149208189184319441">"isinasagawa"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Kumpletuhin ang pagkilos gamit ang"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Tapusin ang pagkilos gamit ang %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Gawin ang pagkilos"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index b7afbde..828a24e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"işaretli değil"</string>
     <string name="selected" msgid="6614607926197755875">"seçili"</string>
     <string name="not_selected" msgid="410652016565864475">"seçili değil"</string>
+    <string name="in_progress" msgid="2149208189184319441">"devam ediyor"</string>
     <string name="whichApplication" msgid="5432266899591255759">"İşlemi şunu kullanarak tamamla"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"İşlemi %1$s kullanarak tamamla"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"İşlemi tamamla"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 10b51ed..a0e7340 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1223,6 +1223,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string>
     <string name="selected" msgid="6614607926197755875">"вибрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не вибрано"</string>
+    <string name="in_progress" msgid="2149208189184319441">"триває"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Що використовувати?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завершити дію за допомогою %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Завершити дію"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index a00b051..fdf288f 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"چیک نہیں کیا گیا"</string>
     <string name="selected" msgid="6614607926197755875">"منتخب کردہ"</string>
     <string name="not_selected" msgid="410652016565864475">"غیر منتخب کردہ"</string>
+    <string name="in_progress" msgid="2149208189184319441">"جاری ہے"</string>
     <string name="whichApplication" msgid="5432266899591255759">"اس کا استعمال کرکے کارروائی مکمل کریں"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏%1$s کا استعمال کر کے کارروائی مکمل کریں"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"کارروائی مکمل کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 045c62d..eabed94 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"belgilanmadi"</string>
     <string name="selected" msgid="6614607926197755875">"tanlangan"</string>
     <string name="not_selected" msgid="410652016565864475">"tanlanmagan"</string>
+    <string name="in_progress" msgid="2149208189184319441">"bajarilmoqda"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Nima ishlatilsin?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"“%1$s” bilan ochish"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Amalni bajarish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index d0e41c1..75bda5f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -602,8 +602,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string>
-    <!-- no translation found for fingerprint_error_bad_calibration (4385512597740168120) -->
-    <skip />
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Không thể dùng cảm biến vân tay. Hãy liên hệ với một nhà cung cấp dịch vụ sửa chữa"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Dùng vân tay"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Dùng vân tay hoặc phương thức khóa màn hình"</string>
@@ -619,12 +618,9 @@
     <string name="face_setup_notification_content" msgid="5463999831057751676">"Mở khóa điện thoại bằng cách nhìn vào điện thoại"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Thiết lập thêm những cách mở khóa khác"</string>
     <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Nhấn để thêm vân tay"</string>
-    <!-- no translation found for fingerprint_recalibrate_notification_name (1414578431898579354) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_title (2406561052064558497) -->
-    <skip />
-    <!-- no translation found for fingerprint_recalibrate_notification_content (8519935717822194943) -->
-    <skip />
+    <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Mở khóa bằng vân tay"</string>
+    <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Không thể dùng cảm biến vân tay"</string>
+    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Hãy liên hệ với một nhà cung cấp dịch vụ sửa chữa."</string>
     <string name="face_acquired_insufficient" msgid="2150805835949162453">"Không thể ghi lại đúng dữ liệu mặt. Hãy thử lại."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Quá sáng. Hãy thử giảm độ sáng."</string>
     <string name="face_acquired_too_dark" msgid="252573548464426546">"Quá tối. Hãy thử tăng độ sáng."</string>
@@ -1187,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"chưa chọn"</string>
     <string name="selected" msgid="6614607926197755875">"đã chọn"</string>
     <string name="not_selected" msgid="410652016565864475">"chưa được chọn"</string>
+    <string name="in_progress" msgid="2149208189184319441">"đang thực hiện"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Hoàn tất thao tác bằng"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất thao tác bằng %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Hoàn thành tác vụ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index eb23130..cdb7e92 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1187,6 +1187,7 @@
     <string name="not_checked" msgid="7972320087569023342">"未勾选"</string>
     <string name="selected" msgid="6614607926197755875">"已选择"</string>
     <string name="not_selected" msgid="410652016565864475">"未选择"</string>
+    <string name="in_progress" msgid="2149208189184319441">"进行中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"选择要使用的应用:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"使用%1$s完成操作"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index c2bce46..a4706b1 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
     <string name="selected" msgid="6614607926197755875">"揀咗"</string>
     <string name="not_selected" msgid="410652016565864475">"未揀"</string>
+    <string name="in_progress" msgid="2149208189184319441">"處理中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"完成操作需使用"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0dae86f..4aab254 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
     <string name="selected" msgid="6614607926197755875">"已選取"</string>
     <string name="not_selected" msgid="410652016565864475">"未選取"</string>
+    <string name="in_progress" msgid="2149208189184319441">"處理中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"選擇要使用的應用程式"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 7ff6bb3..37247d9 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1183,6 +1183,7 @@
     <string name="not_checked" msgid="7972320087569023342">"akuhloliwe"</string>
     <string name="selected" msgid="6614607926197755875">"okukhethiwe"</string>
     <string name="not_selected" msgid="410652016565864475">"akukhethiwe"</string>
+    <string name="in_progress" msgid="2149208189184319441">"kuyaqhubeka"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Qedela isenzo usebenzisa"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Qedela isenzo usebenzisa i-%1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Qedela isenzo"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d052d70..441aa2d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -285,9 +285,6 @@
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the system default text classifier -->
         <flag name="textClassifier" value="0x10000" />
-        <!-- Additional flag from base permission type: this permission can be automatically
-            granted to the document manager -->
-        <flag name="documenter" value="0x40000" />
         <!-- Additional flag from base permission type: this permission automatically
             granted to device configurator -->
         <flag name="configurator" value="0x80000" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 646fbd3..191d7d9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3608,8 +3608,8 @@
     -->
     <integer name="config_largeScreenSmallestScreenWidthDp">600</integer>
 
-    <!-- True if the device is using leagacy split. -->
-    <bool name="config_useLegacySplit">true</bool>
+    <!-- True if the device is using legacy split. -->
+    <bool name="config_useLegacySplit">false</bool>
 
     <!-- True if the device supports running activities on secondary displays. -->
     <bool name="config_supportsMultiDisplay">true</bool>
@@ -4903,13 +4903,21 @@
 
     <bool name="config_cecHdmiCecVersion_userConfigurable">true</bool>
     <bool name="config_cecHdmiCecVersion14b_allowed">true</bool>
-    <bool name="config_cecHdmiCecVersion14b_default">true</bool>
+    <bool name="config_cecHdmiCecVersion14b_default">false</bool>
     <bool name="config_cecHdmiCecVersion20_allowed">true</bool>
-    <bool name="config_cecHdmiCecVersion20_default">false</bool>
+    <bool name="config_cecHdmiCecVersion20_default">true</bool>
+
+    <bool name="config_cecRoutingControl_userConfigurable">true</bool>
+    <bool name="config_cecRoutingControlEnabled_allowed">true</bool>
+    <bool name="config_cecRoutingControlEnabled_default">false</bool>
+    <bool name="config_cecRoutingControlDisabled_allowed">true</bool>
+    <bool name="config_cecRoutingControlDisabled_default">true</bool>
 
     <bool name="config_cecPowerControlMode_userConfigurable">true</bool>
     <bool name="config_cecPowerControlModeTv_allowed">true</bool>
-    <bool name="config_cecPowerControlModeTv_default">true</bool>
+    <bool name="config_cecPowerControlModeTv_default">false</bool>
+    <bool name="config_cecPowerControlModeTvAndAudioSystem_allowed">true</bool>
+    <bool name="config_cecPowerControlModeTvAndAudioSystem_default">true</bool>
     <bool name="config_cecPowerControlModeBroadcast_allowed">true</bool>
     <bool name="config_cecPowerControlModeBroadcast_default">false</bool>
     <bool name="config_cecPowerControlModeNone_allowed">true</bool>
@@ -4921,6 +4929,12 @@
     <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed">true</bool>
     <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">false</bool>
 
+    <bool name="config_cecSystemAudioControl_userConfigurable">true</bool>
+    <bool name="config_cecSystemAudioControlEnabled_allowed">true</bool>
+    <bool name="config_cecSystemAudioControlEnabled_default">true</bool>
+    <bool name="config_cecSystemAudioControlDisabled_allowed">true</bool>
+    <bool name="config_cecSystemAudioControlDisabled_default">false</bool>
+
     <bool name="config_cecSystemAudioModeMuting_userConfigurable">true</bool>
     <bool name="config_cecSystemAudioModeMutingEnabled_allowed">true</bool>
     <bool name="config_cecSystemAudioModeMutingEnabled_default">true</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2403a60..a519cde 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3201,10 +3201,158 @@
     <public type="string" name="config_defaultRingtoneVibrationSound" id="0x0104003b" />
 
   <!-- ===============================================================
+    Resources added in version S-V2 of the platform
+
+    NOTE: add <public> elements within a <staging-public-group> like so:
+
+    <staging-public-group type="attr" first-id="0x01ff0000">
+        <public name="exampleAttr1" />
+        <public name="exampleAttr2" />
+    </staging-public-group>
+
+    To add a new <staging-public-group> block, find the id value for the
+    last <staging-public-group> block defined for thie API level, and
+    subtract 0x00010000 from it to get to the id of the new block.
+
+    For example, if the block closest to the end of this file has an id
+    of 0x01ee0000, the id of the new block should be 0x01ed0000
+    (0x01ee0000 - 0x00010000 = 0x01ed0000).
+    =============================================================== -->
+  <eat-comment />
+
+  <staging-public-group type="attr" first-id="0x01ff0000">
+  </staging-public-group>
+
+  <staging-public-group type="id" first-id="0x01fe0000">
+  </staging-public-group>
+
+  <staging-public-group type="style" first-id="0x01fd0000">
+  </staging-public-group>
+
+  <staging-public-group type="string" first-id="0x01fc0000">
+  </staging-public-group>
+
+  <staging-public-group type="dimen" first-id="0x01fb0000">
+  </staging-public-group>
+
+  <staging-public-group type="color" first-id="0x01fa0000">
+  </staging-public-group>
+
+  <staging-public-group type="array" first-id="0x01f90000">
+  </staging-public-group>
+
+  <staging-public-group type="drawable" first-id="0x01f80000">
+  </staging-public-group>
+
+  <staging-public-group type="layout" first-id="0x01f70000">
+  </staging-public-group>
+
+  <staging-public-group type="anim" first-id="0x01f60000">
+  </staging-public-group>
+
+  <staging-public-group type="animator" first-id="0x01f50000">
+  </staging-public-group>
+
+  <staging-public-group type="interpolator" first-id="0x01f40000">
+  </staging-public-group>
+
+  <staging-public-group type="mipmap" first-id="0x01f30000">
+  </staging-public-group>
+
+  <staging-public-group type="integer" first-id="0x01f20000">
+  </staging-public-group>
+
+  <staging-public-group type="transition" first-id="0x01f10000">
+  </staging-public-group>
+
+  <staging-public-group type="raw" first-id="0x01f00000">
+  </staging-public-group>
+
+  <staging-public-group type="bool" first-id="0x01ef0000">
+  </staging-public-group>
+
+  <staging-public-group type="fraction" first-id="0x01ee0000">
+  </staging-public-group>
+
+  <!-- ===============================================================
+    Resources added in version T of the platform
+
+    NOTE: add <public> elements within a <staging-public-group> like so:
+
+    <staging-public-group type="attr" first-id="0x01ff0000">
+        <public name="exampleAttr1" />
+        <public name="exampleAttr2" />
+    </staging-public-group>
+
+    To add a new <staging-public-group> block, find the id value for the
+    last <staging-public-group> block defined for thie API level, and
+    subtract 0x00010000 from it to get to the id of the new block.
+
+    For example, if the block closest to the end of this file has an id
+    of 0x01ee0000, the id of the new block should be 0x01ed0000
+    (0x01ee0000 - 0x00010000 = 0x01ed0000).
+    =============================================================== -->
+  <eat-comment />
+
+  <staging-public-group type="attr" first-id="0x01df0000">
+  </staging-public-group>
+
+  <staging-public-group type="id" first-id="0x01de0000">
+  </staging-public-group>
+
+  <staging-public-group type="style" first-id="0x0dfd0000">
+  </staging-public-group>
+
+  <staging-public-group type="string" first-id="0x0dfc0000">
+  </staging-public-group>
+
+  <staging-public-group type="dimen" first-id="0x01db0000">
+  </staging-public-group>
+
+  <staging-public-group type="color" first-id="0x01da0000">
+  </staging-public-group>
+
+  <staging-public-group type="array" first-id="0x01d90000">
+  </staging-public-group>
+
+  <staging-public-group type="drawable" first-id="0x01d80000">
+  </staging-public-group>
+
+  <staging-public-group type="layout" first-id="0x01d70000">
+  </staging-public-group>
+
+  <staging-public-group type="anim" first-id="0x01d60000">
+  </staging-public-group>
+
+  <staging-public-group type="animator" first-id="0x01d50000">
+  </staging-public-group>
+
+  <staging-public-group type="interpolator" first-id="0x01d40000">
+  </staging-public-group>
+
+  <staging-public-group type="mipmap" first-id="0x01d30000">
+  </staging-public-group>
+
+  <staging-public-group type="integer" first-id="0x01d20000">
+  </staging-public-group>
+
+  <staging-public-group type="transition" first-id="0x01d10000">
+  </staging-public-group>
+
+  <staging-public-group type="raw" first-id="0x01d00000">
+  </staging-public-group>
+
+  <staging-public-group type="bool" first-id="0x01cf0000">
+  </staging-public-group>
+
+  <staging-public-group type="fraction" first-id="0x01ce0000">
+  </staging-public-group>
+
+  <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
        Any new items (attrs, styles, ids, etc.) *must* be added in a
-       public-group block, as the preceding comment explains.
+       staging-public-group block, as the preceding comment explains.
        Items added outside of a group may have their value recalculated
        every time something new is added to this file.
        =============================================================== -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d1a5cc4..31eac2a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3201,6 +3201,9 @@
     <!-- Default not selected text used by accessibility for an element that can be selected or unselected. [CHAR LIMIT=NONE] -->
     <string name="not_selected">not selected</string>
 
+    <!-- Default state description for indeterminate progressbar. [CHAR LIMIT=NONE] -->
+    <string name="in_progress">in progress</string>
+
     <!-- Title of intent resolver dialog when selecting an application to run. -->
     <string name="whichApplication">Complete action using</string>
     <!-- Title of intent resolver dialog when selecting an application to run
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c05adfd..2382313 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -796,6 +796,7 @@
   <java-symbol type="string" name="ime_action_previous" />
   <java-symbol type="string" name="ime_action_search" />
   <java-symbol type="string" name="ime_action_send" />
+  <java-symbol type="string" name="in_progress" />
   <java-symbol type="string" name="invalidPin" />
   <java-symbol type="string" name="js_dialog_before_unload_positive_button" />
   <java-symbol type="string" name="js_dialog_before_unload_negative_button" />
@@ -4308,9 +4309,17 @@
   <java-symbol type="bool" name="config_cecHdmiCecVersion20_allowed" />
   <java-symbol type="bool" name="config_cecHdmiCecVersion20_default" />
 
+  <java-symbol type="bool" name="config_cecRoutingControl_userConfigurable" />
+  <java-symbol type="bool" name="config_cecRoutingControlEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecRoutingControlEnabled_default" />
+  <java-symbol type="bool" name="config_cecRoutingControlDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecRoutingControlDisabled_default" />
+
   <java-symbol type="bool" name="config_cecPowerControlMode_userConfigurable" />
   <java-symbol type="bool" name="config_cecPowerControlModeTv_allowed" />
   <java-symbol type="bool" name="config_cecPowerControlModeTv_default" />
+  <java-symbol type="bool" name="config_cecPowerControlModeTvAndAudioSystem_allowed" />
+  <java-symbol type="bool" name="config_cecPowerControlModeTvAndAudioSystem_default" />
   <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_allowed" />
   <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_default" />
   <java-symbol type="bool" name="config_cecPowerControlModeNone_allowed" />
@@ -4322,6 +4331,12 @@
   <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed" />
   <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default" />
 
+  <java-symbol type="bool" name="config_cecSystemAudioControl_userConfigurable" />
+  <java-symbol type="bool" name="config_cecSystemAudioControlEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecSystemAudioControlEnabled_default" />
+  <java-symbol type="bool" name="config_cecSystemAudioControlDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecSystemAudioControlDisabled_default" />
+
   <java-symbol type="bool" name="config_cecSystemAudioModeMuting_userConfigurable" />
   <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_allowed" />
   <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_default" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 2650d9f..2be5c47 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -245,6 +245,9 @@
     <!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
     <shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
 
+    <!-- Taiwan -->
+    <shortcode country="tw" pattern="\\d{4}" free="1922" />
+
     <!-- Thailand: 4186001 used by AIS_TH_DCB -->
     <shortcode country="th" pattern="\\d{1,5}" premium="4\\d{6}" free="4186001" />
 
diff --git a/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java b/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java
index c65ef9a..53ba140 100644
--- a/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/AccessibilityServiceTest.java
@@ -16,18 +16,40 @@
 
 package android.accessibilityservice;
 
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 
+import android.content.Context;
 import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
+import android.window.WindowTokenClient;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,6 +64,8 @@
 public class AccessibilityServiceTest {
     private static final String TAG = "AccessibilityServiceTest";
     private static final int CONNECTION_ID = 1;
+    private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
+            TYPE_ACCESSIBILITY_OVERLAY);
 
     private static class AccessibilityServiceTestClass extends AccessibilityService {
         private IAccessibilityServiceClient mCallback;
@@ -49,7 +73,11 @@
 
         AccessibilityServiceTestClass() {
             super();
-            attachBaseContext(InstrumentationRegistry.getContext());
+            Context context = ApplicationProvider.getApplicationContext();
+            final Display display = context.getSystemService(DisplayManager.class)
+                    .getDisplay(DEFAULT_DISPLAY);
+
+            attachBaseContext(context.createTokenContext(new WindowTokenClient(), display));
             mLooper = InstrumentationRegistry.getContext().getMainLooper();
         }
 
@@ -78,14 +106,33 @@
     private @Mock IBinder mMockIBinder;
     private IAccessibilityServiceClient mServiceInterface;
     private AccessibilityServiceTestClass mService;
+    private final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
 
     @Before
-    public void setUp() throws RemoteException {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mService = new AccessibilityServiceTestClass();
+        mService.onCreate();
         mService.setupCallback(mMockClientForCallback);
         mServiceInterface = (IAccessibilityServiceClient) mService.onBind(new Intent());
         mServiceInterface.init(mMockConnection, CONNECTION_ID, mMockIBinder);
+        doAnswer(invocation -> {
+            Object[] args = invocation.getArguments();
+            final int displayId = (int) args[0];
+            final IBinder token = new Binder();
+            WindowManagerGlobal.getWindowManagerService().addWindowToken(token,
+                    TYPE_ACCESSIBILITY_OVERLAY, displayId, null /* options */);
+            mWindowTokens.put(displayId, token);
+            return token;
+        }).when(mMockConnection).getOverlayWindowToken(anyInt());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        for (int i = mWindowTokens.size() - 1; i >= 0; --i) {
+            WindowManagerGlobal.getWindowManagerService().removeWindowToken(
+                    mWindowTokens.valueAt(i), mWindowTokens.keyAt(i));
+        }
     }
 
     @Test
@@ -101,4 +148,79 @@
 
         verify(mMockConnection).getSystemActions();
     }
+
+    @Test
+    public void testAddViewWithA11yServiceDerivedDisplayContext() throws Exception {
+        try (VirtualDisplaySession session = new VirtualDisplaySession()) {
+            final Context context = mService.createDisplayContext(session.getDisplay());
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                    () -> context.getSystemService(WindowManager.class)
+                            .addView(new View(context), mParams)
+            );
+        }
+    }
+
+    @Test
+    public void testAddViewWithA11yServiceDerivedWindowContext() throws Exception {
+        try (VirtualDisplaySession session = new VirtualDisplaySession()) {
+            final Context context = mService.createDisplayContext(session.getDisplay())
+                    .createWindowContext(TYPE_ACCESSIBILITY_OVERLAY, null /* options */);
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                    () -> context.getSystemService(WindowManager.class)
+                            .addView(new View(context), mParams)
+            );
+        }
+    }
+
+    @Test
+    public void testAddViewWithA11yServiceDerivedWindowContextWithDisplay() throws Exception {
+        try (VirtualDisplaySession session = new VirtualDisplaySession()) {
+            final Context context = mService.createWindowContext(session.getDisplay(),
+                    TYPE_ACCESSIBILITY_OVERLAY, null /* options */);
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                    () -> context.getSystemService(WindowManager.class)
+                            .addView(new View(context), mParams)
+            );
+        }
+    }
+
+    @Test(expected = WindowManager.BadTokenException.class)
+    public void testAddViewWithA11yServiceDerivedWindowContextWithDifferentType()
+            throws Exception {
+        try (VirtualDisplaySession session = new VirtualDisplaySession()) {
+            final Context context = mService.createWindowContext(session.getDisplay(),
+                    TYPE_APPLICATION_OVERLAY, null /* options */);
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                    () -> context.getSystemService(WindowManager.class)
+                            .addView(new View(context), mParams)
+            );
+        }
+    }
+
+
+    private static class VirtualDisplaySession implements AutoCloseable {
+        private final VirtualDisplay mVirtualDisplay;
+
+        VirtualDisplaySession() {
+            final DisplayManager displayManager = ApplicationProvider.getApplicationContext()
+                    .getSystemService(DisplayManager.class);
+            final int width = 800;
+            final int height = 480;
+            final int density = 160;
+            ImageReader reader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888,
+                    2 /* maxImages */);
+            mVirtualDisplay = displayManager.createVirtualDisplay(
+                    TAG, width, height, density, reader.getSurface(),
+                    VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
+        }
+
+        private Display getDisplay() {
+            return mVirtualDisplay.getDisplay();
+        }
+
+        @Override
+        public void close() throws Exception {
+            mVirtualDisplay.release();
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 4b0ed65..2c3c1ed 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -26,8 +26,11 @@
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.LargeTest;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import junit.framework.TestCase;
 
 import org.mockito.Mockito;
@@ -110,6 +113,13 @@
         public boolean isAllow3rdPartyOnInternal(Context context) {
             return mAllow3rdPartyOnInternal;
         }
+
+        @Override
+        @VisibleForTesting
+        protected @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app,
+                StorageManager storageManager, IPackageManager pm) {
+            return super.getPackageCandidateVolumes(app, storageManager, pm);
+        }
     }
 
     private StorageManager getMockedStorageManager() {
@@ -223,7 +233,7 @@
             appInfo.flags = 0;
 
             appInfo.volumeUuid = sInternalVolUuid;
-            Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false);
+            Mockito.when(pm.isPackageDeviceAdminOnAnyUser(appInfo.packageName)).thenReturn(false);
             appPkgMgr.setAllow3rdPartyOnInternal(true);
             List<VolumeInfo> candidates = appPkgMgr.getPackageCandidateVolumes(
                     appInfo, storageManager, pm);
@@ -231,7 +241,7 @@
 
             appInfo.volumeUuid = sInternalVolUuid;
             appPkgMgr.setAllow3rdPartyOnInternal(true);
-            Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(true);
+            Mockito.when(pm.isPackageDeviceAdminOnAnyUser(appInfo.packageName)).thenReturn(true);
             candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm);
             verifyReturnedVolumes(candidates, sInternalVol);
 
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index 8488a84..51cdd82 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -39,7 +39,6 @@
 import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
-import android.inputmethodservice.InputMethodService;
 import android.media.ImageReader;
 import android.os.FileUtils;
 import android.os.UserHandle;
@@ -156,13 +155,6 @@
     }
 
     @Test
-    public void testIsUiContext_InputMethodService_returnsTrue() {
-        final InputMethodService ims = new InputMethodService();
-
-        assertTrue(ims.isUiContext());
-    }
-
-    @Test
     public void testGetDisplayFromDisplayContextDerivedContextOnPrimaryDisplay() {
         verifyGetDisplayFromDisplayContextDerivedContext(false /* onSecondaryDisplay */);
     }
diff --git a/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java b/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
index 49b720c..cf7e5c66 100644
--- a/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
+++ b/core/tests/coretests/src/android/content/pm/SigningDetailsTest.java
@@ -15,19 +15,18 @@
  */
 package android.content.pm;
 
-import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.AUTH;
-import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA;
-import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.PERMISSION;
-import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.ROLLBACK;
-import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID;
-import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3;
+import static android.content.pm.SigningDetails.CertCapabilities.AUTH;
+import static android.content.pm.SigningDetails.CertCapabilities.INSTALLED_DATA;
+import static android.content.pm.SigningDetails.CertCapabilities.PERMISSION;
+import static android.content.pm.SigningDetails.CertCapabilities.ROLLBACK;
+import static android.content.pm.SigningDetails.CertCapabilities.SHARED_USER_ID;
+import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.content.pm.PackageParser.SigningDetails;
 import android.util.ArraySet;
 import android.util.PackageUtils;
 
@@ -990,11 +989,11 @@
     private void assertSigningDetailsContainsLineage(SigningDetails details,
             String... pastSigners) {
         // This method should only be invoked for results that contain a single signer.
-        assertEquals(1, details.signatures.length);
-        assertTrue(details.signatures[0].toCharsString().equalsIgnoreCase(
+        assertEquals(1, details.getSignatures().length);
+        assertTrue(details.getSignatures()[0].toCharsString().equalsIgnoreCase(
                 pastSigners[pastSigners.length - 1]));
         Set<String> signatures = new ArraySet<>(pastSigners);
-        for (Signature pastSignature : details.pastSigningCertificates) {
+        for (Signature pastSignature : details.getPastSigningCertificates()) {
             assertTrue(signatures.remove(pastSignature.toCharsString()));
         }
         assertEquals(0, signatures.size());
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index fd39cde..e53fc07 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -773,46 +773,51 @@
 
         try {
             // Ensure the device starts in a known state.
-            DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
+            DeviceConfig.setSyncDisabledMode(Settings.Config.SYNC_DISABLED_MODE_NONE);
 
             // Assert starting state.
-            assertThat(DeviceConfig.isSyncDisabled()).isFalse();
+            assertThat(DeviceConfig.getSyncDisabledMode())
+                    .isEqualTo(Settings.Config.SYNC_DISABLED_MODE_NONE);
             assertThat(DeviceConfig.setProperties(properties1)).isTrue();
             assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
                     .isEqualTo(VALUE);
 
             // Test disabled (persistent). Persistence is not actually tested, that would require
             // a host test.
-            DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_PERSISTENT);
-            assertThat(DeviceConfig.isSyncDisabled()).isTrue();
+            DeviceConfig.setSyncDisabledMode(Settings.Config.SYNC_DISABLED_MODE_PERSISTENT);
+            assertThat(DeviceConfig.getSyncDisabledMode())
+                    .isEqualTo(Settings.Config.SYNC_DISABLED_MODE_PERSISTENT);
             assertThat(DeviceConfig.setProperties(properties2)).isFalse();
             assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
                     .isEqualTo(VALUE);
 
             // Return to not disabled.
-            DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
-            assertThat(DeviceConfig.isSyncDisabled()).isFalse();
+            DeviceConfig.setSyncDisabledMode(Settings.Config.SYNC_DISABLED_MODE_NONE);
+            assertThat(DeviceConfig.getSyncDisabledMode())
+                    .isEqualTo(Settings.Config.SYNC_DISABLED_MODE_NONE);
             assertThat(DeviceConfig.setProperties(properties2)).isTrue();
             assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
                     .isEqualTo(VALUE2);
 
             // Test disabled (persistent). Absence of persistence is not actually tested, that would
             // require a host test.
-            DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT);
-            assertThat(DeviceConfig.isSyncDisabled()).isTrue();
+            DeviceConfig.setSyncDisabledMode(Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT);
+            assertThat(DeviceConfig.getSyncDisabledMode())
+                    .isEqualTo(Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT);
             assertThat(DeviceConfig.setProperties(properties1)).isFalse();
             assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
                     .isEqualTo(VALUE2);
 
             // Return to not disabled.
-            DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
-            assertThat(DeviceConfig.isSyncDisabled()).isFalse();
+            DeviceConfig.setSyncDisabledMode(Settings.Config.SYNC_DISABLED_MODE_NONE);
+            assertThat(DeviceConfig.getSyncDisabledMode())
+                    .isEqualTo(Settings.Config.SYNC_DISABLED_MODE_NONE);
             assertThat(DeviceConfig.setProperties(properties1)).isTrue();
             assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE))
                     .isEqualTo(VALUE);
         } finally {
             // Try to return to the default sync disabled state in case of failure.
-            DeviceConfig.setSyncDisabled(Settings.Config.SYNC_DISABLED_MODE_NONE);
+            DeviceConfig.setSyncDisabledMode(Settings.Config.SYNC_DISABLED_MODE_NONE);
 
             // NAMESPACE will be cleared by cleanUp()
         }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 46c96c9..2c8c385 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -21,6 +21,7 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.view.Display;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -41,14 +42,14 @@
     // and assertAccessibilityEventCleared
 
     /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 33;
+    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 34;
 
     // 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 = 24;
+    private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 25;
 
     @Test
     public void testImportantForAccessibiity_getSetWorkAcrossParceling() {
@@ -69,6 +70,14 @@
     }
 
     @Test
+    public void testSourceDisplayId_getSetWorkAcrossParceling() {
+        final int sourceDisplayId = Display.DEFAULT_DISPLAY;
+        AccessibilityEvent event = AccessibilityEvent.obtain();
+        event.setDisplayId(sourceDisplayId);
+        assertEquals(sourceDisplayId, copyEventViaParcel(event).getDisplayId());
+    }
+
+    @Test
     public void testWindowChanges_getSetWorkAcrossParceling() {
         final int windowChanges = AccessibilityEvent.WINDOWS_CHANGE_TITLE
                 | AccessibilityEvent.WINDOWS_CHANGE_ACTIVE
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 8643a37..3045d7d 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -34,6 +34,8 @@
 public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceConnection.Stub {
     public void setServiceInfo(AccessibilityServiceInfo info) {}
 
+    public void setAttributionTag(String attributionTag) {}
+
     public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
             long accessibilityNodeId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
@@ -166,4 +168,7 @@
 
     public void logTrace(long timestamp, String where, String callingParams, int processId,
             long threadId, int callingUid, Bundle callingStack) {}
+
+    public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
+            int processId, long threadId, int callingUid, Bundle serializedCallingStackInBundle) {}
 }
diff --git a/core/tests/coretests/src/android/widget/ProgressBarTest.java b/core/tests/coretests/src/android/widget/ProgressBarTest.java
new file mode 100644
index 0000000..5b92471
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/ProgressBarTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.platform.test.annotations.Presubmit;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class ProgressBarTest {
+    private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    private ProgressBar mBar;
+    private AccessibilityNodeInfo mInfo;
+
+    @Before
+    public void setUp() throws Exception {
+        // enable accessibility
+        mInstrumentation.getUiAutomation();
+        // create ProgressBar on main thread and call setProgress on main thread
+        mInstrumentation.runOnMainSync(() ->
+                mBar = new ProgressBar(
+                        InstrumentationRegistry.getInstrumentation().getContext(),
+                        null,
+                        com.android.internal.R.attr.progressBarStyleHorizontal
+                )
+        );
+        mInfo = AccessibilityNodeInfo.obtain();
+    }
+
+    @After
+    public void tearDown() {
+        mInfo.recycle();
+    }
+
+    @Test
+    public void testStateDescription_determinateProgressBar_default() {
+        mBar.setIndeterminate(false);
+        assertFalse(mBar.isIndeterminate());
+
+        mInstrumentation.runOnMainSync(() -> mBar.setProgress(50));
+
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("50%", mInfo.getStateDescription().toString());
+    }
+
+    @Test
+    public void testStateDescription_determinateProgressBar_custom_viewApi() {
+        mBar.setIndeterminate(false);
+        assertFalse(mBar.isIndeterminate());
+        // A workaround for the not-attached ProgressBar.
+        mBar.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                info.setStateDescription(host.getStateDescription());
+                super.onInitializeAccessibilityNodeInfo(host, info);
+            }
+        });
+
+        mBar.setStateDescription("custom state");
+        mInstrumentation.runOnMainSync(() -> mBar.setProgress(50));
+
+        assertEquals("custom state", mBar.getStateDescription().toString());
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("custom state", mInfo.getStateDescription().toString());
+
+        mBar.setStateDescription(null);
+
+        assertNull(mBar.getStateDescription());
+        mInfo.recycle();
+        mInfo = AccessibilityNodeInfo.obtain();
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("50%", mInfo.getStateDescription().toString());
+    }
+
+    @Test
+    public void testStateDescription_determinateProgressBar_custom_accessibilityNodeInfoApi() {
+        mBar.setIndeterminate(false);
+        assertFalse(mBar.isIndeterminate());
+        mBar.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.setStateDescription("custom state");
+            }
+        });
+
+        mInstrumentation.runOnMainSync(() -> mBar.setProgress(50));
+
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("custom state", mInfo.getStateDescription().toString());
+    }
+
+    @Test
+    public void testStateDescription_indeterminateProgressBar_default() {
+        mBar.setIndeterminate(true);
+        assertTrue(mBar.isIndeterminate());
+
+        // call setMax to invoke call to ProgressBar#onProgressRefresh()
+        mInstrumentation.runOnMainSync(() -> mBar.setMax(200));
+
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("in progress", mInfo.getStateDescription().toString());
+    }
+
+    @Test
+    public void testStateDescription_indeterminateProgressBar_custom_viewApi() {
+        mBar.setIndeterminate(true);
+        assertTrue(mBar.isIndeterminate());
+        // A workaround for the not-attached ProgressBar.
+        mBar.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                info.setStateDescription(host.getStateDescription());
+                super.onInitializeAccessibilityNodeInfo(host, info);
+            }
+        });
+
+        mBar.setStateDescription("custom state");
+        // call setMax to invoke call to ProgressBar#onProgressRefresh()
+        mInstrumentation.runOnMainSync(() -> mBar.setMax(200));
+
+        assertEquals("custom state", mBar.getStateDescription().toString());
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("custom state", mInfo.getStateDescription().toString());
+
+        mBar.setStateDescription(null);
+
+        assertNull(mBar.getStateDescription());
+        mInfo.recycle();
+        mInfo = AccessibilityNodeInfo.obtain();
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("in progress", mInfo.getStateDescription().toString());
+    }
+
+    @Test
+    public void testStateDescription_indeterminateProgressBar_custom_accessibilityNodeInfoApi() {
+        mBar.setIndeterminate(true);
+        assertTrue(mBar.isIndeterminate());
+        mBar.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.setStateDescription("custom state");
+            }
+        });
+
+        // call setMax to invoke call to ProgressBar#onProgressRefresh()
+        mInstrumentation.runOnMainSync(() -> mBar.setMax(200));
+
+        mBar.onInitializeAccessibilityNodeInfo(mInfo);
+        assertEquals("custom state", mInfo.getStateDescription().toString());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityUtilsTest.java
new file mode 100644
index 0000000..045b3a2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityUtilsTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.accessibility;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.text.ParcelableSpan;
+import android.text.SpannableString;
+import android.text.style.LocaleSpan;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.accessibility.util.AccessibilityUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+/**
+ * Unit tests for AccessibilityUtils.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityUtilsTest {
+    @Test
+    public void textOrSpanChanged_stringChange_returnTextChange() {
+        final CharSequence beforeText = "a";
+
+        final CharSequence afterText = "b";
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.TEXT, type);
+    }
+
+    @Test
+    public void textOrSpanChanged_stringNotChange_returnNoneChange() {
+        final CharSequence beforeText = "a";
+
+        final CharSequence afterText = "a";
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.NONE, type);
+    }
+
+    @Test
+    public void textOrSpanChanged_nonSpanToNonParcelableSpan_returnNoneChange() {
+        final Object nonParcelableSpan = new Object();
+        final CharSequence beforeText = new SpannableString("a");
+
+        final SpannableString afterText = new SpannableString("a");
+        afterText.setSpan(nonParcelableSpan, 0, 1, 0);
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.NONE, type);
+    }
+
+    @Test
+    public void textOrSpanChanged_nonSpanToParcelableSpan_returnParcelableSpanChange() {
+        final ParcelableSpan parcelableSpan = new LocaleSpan(Locale.ENGLISH);
+        final CharSequence beforeText = new SpannableString("a");
+
+        final SpannableString afterText = new SpannableString("a");
+        afterText.setSpan(parcelableSpan, 0, 1, 0);
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.PARCELABLE_SPAN, type);
+    }
+
+    @Test
+    public void textOrSpanChanged_nonParcelableSpanToParcelableSpan_returnParcelableSpanChange() {
+        final Object nonParcelableSpan = new Object();
+        final ParcelableSpan parcelableSpan = new LocaleSpan(Locale.ENGLISH);
+        final SpannableString beforeText = new SpannableString("a");
+        beforeText.setSpan(nonParcelableSpan, 0, 1, 0);
+
+        SpannableString afterText = new SpannableString("a");
+        afterText.setSpan(parcelableSpan, 0, 1, 0);
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.PARCELABLE_SPAN, type);
+    }
+
+    @Test
+    public void textOrSpanChanged_nonParcelableSpanChange_returnNoneChange() {
+        final Object nonParcelableSpan = new Object();
+        final SpannableString beforeText = new SpannableString("a");
+        beforeText.setSpan(nonParcelableSpan, 0, 1, 0);
+
+        final SpannableString afterText = new SpannableString("a");
+        afterText.setSpan(nonParcelableSpan, 1, 1, 0);
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.NONE, type);
+    }
+
+    @Test
+    public void textOrSpanChanged_parcelableSpanChange_returnParcelableSpanChange() {
+        final ParcelableSpan parcelableSpan = new LocaleSpan(Locale.ENGLISH);
+        final SpannableString beforeText = new SpannableString("a");
+        beforeText.setSpan(parcelableSpan, 0, 1, 0);
+
+        final SpannableString afterText = new SpannableString("a");
+        afterText.setSpan(parcelableSpan, 1, 1, 0);
+
+        @AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
+                beforeText, afterText);
+        assertEquals(AccessibilityUtils.PARCELABLE_SPAN, type);
+    }
+}
diff --git a/core/tests/mockingcoretests/src/android/window/ConfigurationHelperTest.java b/core/tests/mockingcoretests/src/android/window/ConfigurationHelperTest.java
new file mode 100644
index 0000000..996d7b4
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/window/ConfigurationHelperTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+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.Mockito.mock;
+
+import android.app.ResourcesManager;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/**
+ * Tests for {@link ConfigurationHelper}
+ *
+ * <p>Build/Install/Run:
+ *  atest FrameworksMockingCoreTests:ConfigurationHelperTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class ConfigurationHelperTest {
+    MockitoSession mMockitoSession;
+    ResourcesManager mResourcesManager;
+
+    @Before
+    public void setUp() {
+        mMockitoSession = mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .spyStatic(ResourcesManager.class)
+                .startMocking();
+        doReturn(mock(ResourcesManager.class)).when(ResourcesManager::getInstance);
+        mResourcesManager = ResourcesManager.getInstance();
+    }
+
+    @After
+    public void tearDown() {
+        mMockitoSession.finishMocking();
+    }
+
+    @Test
+    public void testShouldUpdateResources_NullConfig_ReturnsTrue() {
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), null /* config */,
+                new Configuration(), new Configuration(), false /* displayChanged */,
+                null /* configChanged */)).isTrue();
+    }
+
+    @Test
+    public void testShouldUpdateResources_DisplayChanged_ReturnsTrue() {
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), new Configuration(),
+                new Configuration(), new Configuration(), true /* displayChanged */,
+                null /* configChanged */)).isTrue();
+    }
+
+    @Test
+    public void testShouldUpdateResources_DifferentResources_ReturnsTrue() {
+        doReturn(false).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
+
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), new Configuration(),
+                new Configuration(), new Configuration(), false /* displayChanged */,
+                null /* configChanged */)).isTrue();
+    }
+
+    @Test
+    public void testShouldUpdateResources_DifferentBounds_ReturnsTrue() {
+        doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
+
+        final Configuration config = new Configuration();
+        config.windowConfiguration.setBounds(new Rect(0, 0, 10, 10));
+        config.windowConfiguration.setMaxBounds(new Rect(0, 0, 20, 20));
+
+        final Configuration newConfig = new Configuration();
+        newConfig.windowConfiguration.setBounds(new Rect(0, 0, 20, 20));
+        newConfig.windowConfiguration.setMaxBounds(new Rect(0, 0, 20, 20));
+
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
+                new Configuration(), false /* displayChanged */, null /* configChanged */))
+                .isTrue();
+    }
+
+    @Test
+    public void testShouldUpdateResources_SameConfig_ReturnsFalse() {
+        doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
+
+        final Configuration config = new Configuration();
+        final Configuration newConfig = new Configuration();
+
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
+                new Configuration(), false /* displayChanged */, null /* configChanged */))
+                .isFalse();
+    }
+
+    @Test
+    public void testShouldUpdateResources_DifferentConfig_ReturnsTrue() {
+        doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
+
+        final Configuration config = new Configuration();
+        final Configuration newConfig = new Configuration();
+        newConfig.setToDefaults();
+
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
+                new Configuration(), false /* displayChanged */, null /* configChanged */))
+                .isTrue();
+    }
+
+    @Test
+    public void testShouldUpdateResources_DifferentNonPublicConfig_ReturnsTrue() {
+        doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
+
+        final Configuration config = new Configuration();
+        final Configuration newConfig = new Configuration();
+        newConfig.windowConfiguration.setAppBounds(new Rect(0, 0, 10, 10));
+
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
+                new Configuration(), false /* displayChanged */, null /* configChanged */))
+                .isTrue();
+    }
+
+    @Test
+    public void testShouldUpdateResources_OverrideConfigChanged_ReturnsFalse() {
+        doReturn(true).when(mResourcesManager).isSameResourcesOverrideConfig(any(), any());
+
+        final Configuration config = new Configuration();
+        final Configuration newConfig = new Configuration();
+        final boolean configChanged = true;
+
+        assertThat(ConfigurationHelper.shouldUpdateResources(new Binder(), config, newConfig,
+                new Configuration(), false /* displayChanged */, configChanged))
+                .isEqualTo(configChanged);
+    }
+}
diff --git a/data/etc/car/com.android.car.activityresolver.xml b/data/etc/car/com.android.car.activityresolver.xml
index d48bc15..927c738 100644
--- a/data/etc/car/com.android.car.activityresolver.xml
+++ b/data/etc/car/com.android.car.activityresolver.xml
@@ -19,3 +19,4 @@
         <permission name="android.permission.MANAGE_USERS"/>
     </privapp-permissions>
 </permissions>
+
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 6385952..8f5273e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -341,6 +341,8 @@
         <!-- Needed for test only -->
         <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
         <permission name="android.permission.POWER_SAVER" />
+        <!-- Needed for CTS tests -->
+        <permission name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"/>
         <permission name="android.permission.READ_CARRIER_APP_INFO"/>
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
@@ -532,6 +534,11 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.wallpaper.livepicker">
+        <permission name="android.permission.SET_WALLPAPER_COMPONENT"/>
+        <permission name="android.permission.BIND_WALLPAPER"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.dynsystem">
         <permission name="android.permission.REBOOT"/>
         <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index ac5e2d0..bfd12f8 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -103,6 +103,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "-2010331310": {
+      "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-2006946193": {
       "message": "setClientVisible: %s clientVisible=%b Callers=%s",
       "level": "VERBOSE",
@@ -211,6 +217,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
     },
+    "-1886145147": {
+      "message": "resumeTopActivity: Going to sleep and all paused",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1884933373": {
       "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
       "level": "INFO",
@@ -247,12 +259,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
-    "-1861864501": {
-      "message": "resumeTopActivityLocked: Going to sleep and all paused",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-1844540996": {
       "message": "  Initial targets: %s",
       "level": "VERBOSE",
@@ -325,12 +331,6 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
-    "-1768090656": {
-      "message": "Re-launching after pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-1750384749": {
       "message": "Launch on display check: allow launch on public display",
       "level": "DEBUG",
@@ -415,12 +415,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-1655805455": {
-      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-1647332198": {
       "message": "remove RecentTask %s when finishing user %d",
       "level": "INFO",
@@ -433,6 +427,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
     },
+    "-1633115609": {
+      "message": "Key dispatch not paused for screen off",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1632122349": {
       "message": "Changing surface while display frozen: %s",
       "level": "VERBOSE",
@@ -487,6 +487,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-1564228464": {
+      "message": "App died while pausing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1559645910": {
       "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
       "level": "DEBUG",
@@ -565,12 +571,6 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
-    "-1492696222": {
-      "message": "App died during pause, not stopping: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-1480772131": {
       "message": "No app or window is requesting an orientation, return %d for display id=%d",
       "level": "VERBOSE",
@@ -637,12 +637,24 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1421296808": {
+      "message": "Moving to RESUMED: %s (in existing)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1419762046": {
       "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d",
       "level": "DEBUG",
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "-1419461256": {
+      "message": "resumeTopActivity: Resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1413901262": {
       "message": "startRecentsActivity(): intent=%s",
       "level": "DEBUG",
@@ -709,6 +721,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-1311436264": {
+      "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "-1305966693": {
       "message": "Sending position change to %s, onTop: %b",
       "level": "VERBOSE",
@@ -805,6 +823,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-1187377055": {
+      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-1176488860": {
       "message": "SURFACE isSecure=%b: %s",
       "level": "INFO",
@@ -919,12 +943,6 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
-    "-1066383762": {
-      "message": "Sleep still waiting to pause %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-1060365734": {
       "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
       "level": "WARN",
@@ -985,6 +1003,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "-957060823": {
+      "message": "Moving to PAUSING: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-951939129": {
       "message": "Unregister task organizer=%s uid=%d",
       "level": "VERBOSE",
@@ -1201,6 +1225,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-706481945": {
+      "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "-705939410": {
       "message": "Waiting for pause to complete...",
       "level": "VERBOSE",
@@ -1237,12 +1267,6 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
-    "-672228342": {
-      "message": "resumeTopActivityLocked: Top activity resumed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-668956537": {
       "message": "  THUMBNAIL %s: CREATE",
       "level": "INFO",
@@ -1267,11 +1291,11 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
-    "-650261962": {
-      "message": "Sleep needs to pause %s",
+    "-648891906": {
+      "message": "Activity not running or entered PiP, resuming next.",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
     "-641258376": {
       "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
@@ -1309,12 +1333,6 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-606328116": {
-      "message": "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-597091183": {
       "message": "Delete TaskDisplayArea uid=%d",
       "level": "VERBOSE",
@@ -1375,11 +1393,11 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowAnimator.java"
     },
-    "-533690126": {
-      "message": "resumeTopActivityLocked: Resumed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
+    "-542756093": {
+      "message": "TaskFragment vanished name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
     },
     "-532081937": {
       "message": "  Commit activity becoming invisible: %s",
@@ -1387,11 +1405,11 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
-    "-527683022": {
-      "message": "resumeTopActivityLocked: Skip resume: some activity pausing.",
+    "-521613870": {
+      "message": "App died during pause, not stopping: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
     "-519504830": {
       "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
@@ -1477,18 +1495,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
-    "-427457280": {
-      "message": "App died while pausing: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-417514857": {
-      "message": "Key dispatch not paused for screen off",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-415865166": {
       "message": "findFocusedWindow: Found new focus @ %s",
       "level": "VERBOSE",
@@ -1597,11 +1603,17 @@
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/LockTaskController.java"
     },
-    "-303497363": {
-      "message": "reparent: moving activity=%s to task=%d at %d",
+    "-312353598": {
+      "message": "Executing finish of activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-310337305": {
+      "message": "Activity config changed during resume: %s, new next: %s",
       "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
     "-302468788": {
       "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
@@ -1621,12 +1633,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-279436615": {
-      "message": "Moving to PAUSING: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-262984451": {
       "message": "Relaunch failed %s",
       "level": "INFO",
@@ -1639,6 +1645,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "-248761393": {
+      "message": "startPausing: taskFrag =%s mResumedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-240296576": {
       "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
       "level": "VERBOSE",
@@ -1651,12 +1663,6 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "-234244777": {
-      "message": "Activity config changed during resume: %s, new next: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-230587670": {
       "message": "SyncGroup %d:  Unfinished container: %s",
       "level": "VERBOSE",
@@ -1723,12 +1729,6 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "-118786523": {
-      "message": "Resume failed; resetting state to %s: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "-116086365": {
       "message": "******************** ENABLING SCREEN!",
       "level": "INFO",
@@ -1777,6 +1777,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/Session.java"
     },
+    "-80004683": {
+      "message": "Resume failed; resetting state to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "-50336993": {
       "message": "moveFocusableActivityToTop: activity=%s",
       "level": "DEBUG",
@@ -1909,12 +1915,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
     },
-    "94402792": {
-      "message": "Moving to RESUMED: %s (in existing)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "95216706": {
       "message": "hideIme target: %s ",
       "level": "DEBUG",
@@ -1933,6 +1933,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "102618780": {
+      "message": "resumeTopActivity: Pausing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "108170907": {
       "message": "Add starting %s: startingData=%s",
       "level": "VERBOSE",
@@ -2173,6 +2179,18 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "327461496": {
+      "message": "Complete pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "341055768": {
+      "message": "resumeTopActivity: Skip resume: need to start pausing",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "342460966": {
       "message": "DRAG %s: pos=(%d,%d)",
       "level": "INFO",
@@ -2227,11 +2245,11 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "391189028": {
-      "message": "pauseBackTasks: task=%s mResumedActivity=%s",
-      "level": "DEBUG",
+    "378825104": {
+      "message": "Enqueueing pending pause: %s",
+      "level": "VERBOSE",
       "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
     "397105698": {
       "message": "grantEmbeddedWindowFocus remove request for win=%s dropped since no candidate was found",
@@ -2365,6 +2383,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
     },
+    "573582981": {
+      "message": "reparent: moving activity=%s to new task fragment in task=%d at %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "579298675": {
       "message": "Moving to DESTROYED: %s (removed from history)",
       "level": "VERBOSE",
@@ -2467,6 +2491,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "660908897": {
+      "message": "Auto-PIP allowed, entering PIP mode directly: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "662572728": {
       "message": "Attempted to add a toast window with bad token %s.  Aborting.",
       "level": "WARN",
@@ -2485,12 +2515,24 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "669361121": {
+      "message": "Sleep still need to stop %d activities",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "674932310": {
       "message": "Setting Intent of %s to target %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/Task.java"
     },
+    "675705156": {
+      "message": "resumeTopActivity: Top activity resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "685047360": {
       "message": "Resizing window %s",
       "level": "VERBOSE",
@@ -2521,12 +2563,6 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
     },
-    "709500946": {
-      "message": "resumeTopActivityLocked: Skip resume: need to start pausing",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "715749922": {
       "message": "Allowlisting %d:%s",
       "level": "WARN",
@@ -2629,12 +2665,6 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
-    "897964776": {
-      "message": "Complete pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "898863925": {
       "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
       "level": "WARN",
@@ -2659,6 +2689,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
     },
+    "935418348": {
+      "message": "resumeTopActivity: Skip resume: some activity pausing.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "950074526": {
       "message": "setLockTaskMode: Can't lock due to auth",
       "level": "WARN",
@@ -2707,11 +2743,11 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
     },
-    "988389910": {
-      "message": "resumeTopActivityLocked: Pausing %s",
-      "level": "DEBUG",
+    "987903142": {
+      "message": "Sleep needs to pause %s",
+      "level": "VERBOSE",
       "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
     "996960396": {
       "message": "Starting Transition %d",
@@ -2719,18 +2755,24 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
-    "1001509841": {
-      "message": "Auto-PIP allowed, entering PIP mode directly: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "1001904964": {
       "message": "***** BOOT TIMEOUT: forcing display enabled",
       "level": "WARN",
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "1011462000": {
+      "message": "Re-launching after pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "1022095595": {
+      "message": "TaskFragment info changed name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "1023413388": {
       "message": "Finish waiting for pause of: %s",
       "level": "VERBOSE",
@@ -2917,6 +2959,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1284122013": {
+      "message": "TaskFragment appeared name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "1288731814": {
       "message": "WindowState.hideLw: setting mFocusMayChange true",
       "level": "INFO",
@@ -3163,12 +3211,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
       "at": "com\/android\/server\/wm\/WindowContainer.java"
     },
-    "1585450696": {
-      "message": "resumeTopActivityLocked: Restarting %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "1589610525": {
       "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
       "level": "VERBOSE",
@@ -3217,6 +3259,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "1653025361": {
+      "message": "Register task fragment organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
     "1653210583": {
       "message": "Removing app %s delayed=%b animation=%s animating=%b",
       "level": "VERBOSE",
@@ -3385,18 +3433,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1837992242": {
-      "message": "Executing finish of activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "1847414670": {
-      "message": "Activity not running or entered PiP, resuming next.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "1853793312": {
       "message": "Notify removed startingWindow %s",
       "level": "VERBOSE",
@@ -3409,6 +3445,12 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1856783490": {
+      "message": "resumeTopActivity: Restarting %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "1865125884": {
       "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b",
       "level": "DEBUG",
@@ -3421,30 +3463,24 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "1884961873": {
-      "message": "Sleep still need to stop %d activities",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "1891501279": {
       "message": "cancelAnimation(): reason=%s",
       "level": "DEBUG",
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
-    "1894239744": {
-      "message": "Enqueueing pending pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
     "1903353011": {
       "message": "notifyAppStopped: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1912291550": {
+      "message": "Sleep still waiting to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
     "1918448345": {
       "message": "Task appeared taskId=%d",
       "level": "VERBOSE",
diff --git a/data/keyboards/Vendor_0171_Product_0419.kl b/data/keyboards/Vendor_0171_Product_0419.kl
new file mode 100644
index 0000000..05a25f0
--- /dev/null
+++ b/data/keyboards/Vendor_0171_Product_0419.kl
@@ -0,0 +1,55 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Amazon Luna Controller
+#
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Left and right stick.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x02 Z flat 4096
+axis 0x05 RZ flat 4096
+
+# Triggers.
+axis 0x0a LTRIGGER
+axis 0x09 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Action button (circle icon, left of the Home button)
+key 158   BUTTON_SELECT
+
+# Home button (branded button in the center of the controller)
+key 172   BUTTON_MODE
+
+# Menu button (hamburger icon, right of the Home button)
+key 315   BUTTON_START
+
+# Alexa Push-To-Talk button (microphone icon, below the Home button)
+key 217   MEDIA_RECORD
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallChecker.java
new file mode 100644
index 0000000..3d7b94f
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallChecker.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.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.instanceMethod;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
+
+@AutoService(BugChecker.class)
+@BugPattern(
+    name = "AndroidFrameworkUnattributedNoteOpCall",
+    summary = "Verifies that a noteOp() call is attributed",
+    severity = WARNING)
+public final class UnattributedNoteOpCallChecker extends BugChecker
+        implements MethodInvocationTreeMatcher {
+
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOP_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteOp(int,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOP_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteOp(java.lang.String,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOP_CALL_3 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteOp(int)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOPNOTHROW_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteOpNoThrow(int,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOPNOTHROW_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteOpNoThrow(java.lang.String,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOP_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOp(java.lang.String,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOP_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOp(int,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOP_CALL_3 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOp(int)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOP_CALL_4 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOp(int,int,java.lang.String,boolean)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOPNOTHROW_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOpNoThrow(java.lang.String,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOPNOTHROW_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOpNoThrow(int,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_STARTOPNOTHROW_CALL_3 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("startOpNoThrow(int,int,java.lang.String,boolean)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEPROXYOP_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteProxyOp(java.lang.String,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEPROXYOP_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteProxyOp(int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEPROXYOPNOTHROW_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteProxyOpNoThrow(java.lang.String,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEPROXYOPNOTHROW_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("noteProxyOpNoThrow(java.lang.String,java.lang.String,int)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_FINISHOP_CALL_1 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("finishOp(int)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_FINISHOP_CALL_2 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("finishOp(java.lang.String,int,java.lang.String)"));
+    private static final Matcher<ExpressionTree> UNATTRIBUTED_FINISHOP_CALL_3 = methodInvocation(
+            instanceMethod().onExactClass("android.app.AppOpsManager")
+                    .withSignature("finishOp(int,int,java.lang.String)"));
+
+    @Override
+    public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
+        if (UNATTRIBUTED_NOTEOP_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_NOTEOP_CALL_2.matches(tree, state)
+            || UNATTRIBUTED_NOTEOP_CALL_3.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed noteOp call! Please use noteOp(int, String, String, String) or noteOp(int, CallerIdentity)")
+                .build();
+        }
+        if (UNATTRIBUTED_NOTEOPNOTHROW_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_NOTEOPNOTHROW_CALL_2.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed noteOpNoThrow call! Please use noteOpNoThrow(String, int, String, String, String)")
+                .build();
+        }
+        if (UNATTRIBUTED_STARTOP_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_STARTOP_CALL_2.matches(tree, state)
+            || UNATTRIBUTED_STARTOP_CALL_3.matches(tree, state)
+            || UNATTRIBUTED_STARTOP_CALL_4.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed startOp call! Please use startOp(int, int, String, boolean, String, String)")
+                .build();
+        }
+        if (UNATTRIBUTED_STARTOPNOTHROW_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_STARTOPNOTHROW_CALL_2.matches(tree, state)
+            || UNATTRIBUTED_STARTOPNOTHROW_CALL_3.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed startOpNoThrow call!")
+                .build();
+        }
+        if (UNATTRIBUTED_NOTEPROXYOP_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_NOTEPROXYOP_CALL_2.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed noteProxyOp call!")
+                .build();
+        }
+        if (UNATTRIBUTED_NOTEPROXYOPNOTHROW_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_NOTEPROXYOPNOTHROW_CALL_2.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed noteProxyOpNoThrow call!")
+                .build();
+        }
+        if (UNATTRIBUTED_FINISHOP_CALL_1.matches(tree, state)
+            || UNATTRIBUTED_FINISHOP_CALL_2.matches(tree, state)
+            || UNATTRIBUTED_FINISHOP_CALL_3.matches(tree, state)) {
+            return buildDescription(tree)
+                .setMessage("Unattributed finishOp call!")
+                .build();
+        }
+
+
+
+        return Description.NO_MATCH;
+    }
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallCheckerTest.java
new file mode 100644
index 0000000..9a98c7c
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallCheckerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import com.google.errorprone.CompilationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class UnattributedNoteOpCallCheckerTest {
+    private CompilationTestHelper mCompilationHelper;
+
+    @Before
+    public void setUp() {
+        mCompilationHelper = CompilationTestHelper.newInstance(
+                UnattributedNoteOpCallChecker.class, getClass());
+    }
+
+    @Test
+    public void testNoteOp() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    mAppOps.noteOp(\"foo\", 0, \"bar\", \"baz\", \"qux\");",
+                        "    mAppOps.noteOp(0, 0, \"bar\", \"baz\", \"qux\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteOp(1, 2, \"foo\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteOp(\"foo\", 1, \"bar\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteOp(1);",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testNoteOpNoThrow() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteOpNoThrow(0, 1, \"foo\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteOpNoThrow(\"foo\", 1, \"bar\");",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testStartOp() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOp(0, 0, \"bar\", true);",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOp(1, 2, \"foo\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOp(\"foo\", 1, \"bar\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOp(1);",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testStartOpNoThrow() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOpNoThrow(0, 0, \"bar\", true);",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOpNoThrow(1, 2, \"foo\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.startOpNoThrow(\"foo\", 1, \"bar\");",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testNoteProxyOp() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteProxyOp(1, \"foo\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteProxyOp(\"foo\", \"bar\");",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testNoteProxyOpNoThrow() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteProxyOpNoThrow(\"foo\", \"bar\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.noteProxyOpNoThrow(\"foo\", \"bar\", 1);",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+    @Test
+    public void testFinishOp() {
+        mCompilationHelper
+                .addSourceFile("/android/app/AppOpsManager.java")
+                .addSourceLines("Example.java",
+                        "import android.app.AppOpsManager;",
+                        "public class Example {",
+                        "  void example() {",
+                        "    AppOpsManager mAppOps = new AppOpsManager();",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.finishOp(1, 2, \"foo\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.finishOp(\"foo\", 1, \"bar\");",
+                        "    // BUG: Diagnostic contains:",
+                        "    mAppOps.finishOp(1);",
+                        "  }",
+                        "}")
+                .doTest();
+    }
+
+
+
+}
diff --git a/errorprone/tests/res/android/app/AppOpsManager.java b/errorprone/tests/res/android/app/AppOpsManager.java
new file mode 100644
index 0000000..216270c
--- /dev/null
+++ b/errorprone/tests/res/android/app/AppOpsManager.java
@@ -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.
+ */
+
+package android.app;
+
+public class AppOpsManager {
+
+    public int noteOp(String op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteOp(int op) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteOp(int op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteOp(String op, int uid, String packageName,
+            String attributionTag, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteOp(int op, int uid, String packageName,
+            String attributionTag, String message) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteOpNoThrow(String op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteOpNoThrow(int op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOp(int op) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOp(int op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOp(int op, int uid, String packageName, boolean startIfModeDefault) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOp(String op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOpNoThrow(String op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOpNoThrow(int op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int startOpNoThrow(int op, int uid, String packageName, boolean startIfModeDefault) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteProxyOp(String op, String proxiedPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteProxyOp(int op, String proxiedPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteProxyOpNoThrow(String op, String proxiedPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int noteProxyOpNoThrow(String op, String proxiedPackageName,
+            int proxiedUid) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void finishOp(int op) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void finishOp(String op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void finishOp(int op, int uid, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/libs/WindowManager/Shell/res/layout/split_outline.xml b/libs/WindowManager/Shell/res/layout/split_outline.xml
new file mode 100644
index 0000000..4e2a77f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/split_outline.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.wm.shell.splitscreen.OutlineRoot
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.wm.shell.splitscreen.OutlineView
+        android:id="@+id/split_outline"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent" />
+
+</com.android.wm.shell.splitscreen.OutlineRoot>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index ea634cf..69aa31e 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Slaan oor na volgende"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Slaan oor na vorige"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Verander grootte"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Hou vas"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Laat los"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Program sal dalk nie met verdeelde skerm werk nie."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Program steun nie verdeelde skerm nie."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Program sal dalk nie op \'n sekondêre skerm werk nie."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Borrel"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Het dit"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index e4628d7..c754e3ca 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ወደ ቀጣይ ዝለል"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ወደ ቀዳሚ ዝለል"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"መጠን ይቀይሩ"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"አረፋ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ያቀናብሩ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"አረፋ ተሰናብቷል።"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ይህን መተግበሪያ ዳግም ለማስነሳት መታ ያድርጉ እና ወደ ሙሉ ማያ ገጽ ይሂዱ።"</string>
+    <string name="got_it" msgid="4428750913636945527">"ገባኝ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 7b5bda7..ac72a3d 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"التخطي إلى التالي"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"التخطي إلى السابق"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغيير الحجم"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"إخفاء"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"إظهار"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"قد لا يعمل التطبيق بشكل سليم في وضع \"تقسيم الشاشة\"."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"التطبيق لا يتيح تقسيم الشاشة."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"فقاعة"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"إدارة"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"تم إغلاق الفقاعة."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"انقر لإعادة تشغيل هذا التطبيق والانتقال إلى وضع ملء الشاشة."</string>
+    <string name="got_it" msgid="4428750913636945527">"حسنًا"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 47294c4..1ace3cd 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"পৰৱৰ্তী মিডিয়ালৈ যাওক"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"আগৰটো মিডিয়ালৈ যাওক"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"আকাৰ সলনি কৰক"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"লুকুৱাওক"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"দেখুৱাওক"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"এপ্‌টোৱে বিভাজিত স্ক্ৰীনৰ সৈতে কাম নকৰিব পাৰে।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপটোৱে বিভাজিত স্ক্ৰীণ সমৰ্থন নকৰে।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"পৰিচালনা কৰক"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"এপ্‌টো ৰিষ্টাৰ্ট কৰিবলৈ আৰু পূৰ্ণ স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ টিপক।"</string>
+    <string name="got_it" msgid="4428750913636945527">"বুজি পালোঁ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 923ff79..6d3e0a9 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Növbətiyə keçin"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Əvvəlkinə keçin"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ölçüsünü dəyişin"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Güvənli məkanda saxlayın"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Güvənli məkandan çıxarın"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string>
@@ -43,10 +45,10 @@
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
     <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yuxarı 30%"</string>
     <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Aşağı tam ekran"</string>
-    <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bir əlli rejimdən istifadə edilir"</string>
+    <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Birəlli rejim istifadəsi"</string>
     <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Çıxmaq üçün ekranın aşağısından yuxarıya doğru sürüşdürün və ya tətbiqin yuxarısında istənilən yerə toxunun"</string>
-    <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bir əlli rejimi başladın"</string>
-    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Bir əlli rejimdən çıxın"</string>
+    <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Birəlli rejim başlasın"</string>
+    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Birəlli rejimdən çıxın"</string>
     <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> yumrucuqları üçün ayarlar"</string>
     <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Kənara çıxma"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Yenidən dəstəyə əlavə edin"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Qabarcıq"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Anladım"</string>
 </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 02e609cd..358da25 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Pređi na sledeće"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pređi na prethodno"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promenite veličinu"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavite u tajnu memoriju"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Uklonite iz tajne memorije"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi sa podeljenim ekranom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podeljeni ekran."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Važi"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index ccea318..7a934cc 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Перайсці да наступнага"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Перайсці да папярэдняга"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змяніць памер"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Схаваць"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Паказаць"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Праграма можа не працаваць у рэжыме падзеленага экрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Усплывальнае апавяшчэнне"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Націсніце, каб перазапусціць гэту праграму і перайсці ў поўнаэкранны рэжым."</string>
+    <string name="got_it" msgid="4428750913636945527">"Зразумела"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index d29660b..02930b1 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Към следващия елемент"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Към предишния елемент"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Преоразмеряване"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Съхраняване"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Отмяна на съхраняването"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Приложението може да не работи в режим на разделен екран."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложението не поддържа разделен екран."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управление"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отхвърлено."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Докоснете, за да рестартирате това приложение в режим на цял екран."</string>
+    <string name="got_it" msgid="4428750913636945527">"Разбрах"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 84bcaf9..b35e179 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"এগিয়ে যাওয়ার জন্য এড়িয়ে যান"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"পিছনে যাওয়ার জন্য এড়িয়ে যান"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"রিসাইজ করুন"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"স্ট্যাস করুন"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"আনস্ট্যাস করুন"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"অ্যাপটি স্প্লিট স্ক্রিনে কাজ নাও করতে পারে।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রিন সমর্থন করে না৷"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ম্যানেজ করুন"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল বাতিল করা হয়েছে।"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"এই অ্যাপ রিস্টার্ট করতে ট্যাপ করুন ও \'ফুল-স্ক্রিন\' মোড ব্যবহার করুন।"</string>
+    <string name="got_it" msgid="4428750913636945527">"বুঝেছি"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 85e08d7..14d90a4 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na sljedeći"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prethodni"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavljanje u stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vađenje iz stasha"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi na podijeljenom ekranu."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava dijeljenje ekrana."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Razumijem"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index a80b7fb..9cffbdd 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Ves al següent"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Torna a l\'anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'aplicació no admet la pantalla dividida."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bombolla"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Entesos"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index e8257bc..9b5206a 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Přeskočit na další"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Přeskočit na předchozí"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Změnit velikost"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Uložit"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušit uložení"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Rozumím"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 17f8286..a06abf1 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Gå videre til næste"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Gå til forrige"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Rediger størrelse"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skjul"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vis"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen fungerer muligvis ikke i opdelt skærm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen understøtter ikke opdelt skærm."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index f04796a..c5e79f8 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Vorwärts springen"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Rückwärts springen"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Größe anpassen"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"In Stash legen"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Aus Stash entfernen"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen bei geteiltem Bildschirmmodus nicht."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
@@ -60,13 +62,15 @@
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Bubble schließen"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Unterhaltung nicht als Bubble anzeigen"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bubbles zum Chatten verwenden"</string>
-    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Neue Unterhaltungen erscheinen als unverankerte Symbole, \"Bubbles\" genannt. Wenn du die Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
+    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Neue Unterhaltungen erscheinen als unverankerte Symbole, „Bubbles“ genannt. Wenn du eine Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Bubble-Einstellungen festlegen"</string>
-    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tippe auf \"Verwalten\", um Bubbles für diese App zu deaktivieren"</string>
+    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tippe auf „Verwalten“, um Bubbles für diese App zu deaktivieren"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Keine kürzlich geschlossenen Bubbles"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Ok"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index cc329e8..fc397c5 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Μετάβαση στο επόμενο"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Μετάβαση στο προηγούμενο"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Αλλαγή μεγέθους"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Απόκρυψη"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Κατάργηση απόκρυψης"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Η εφαρμογή ενδέχεται να μην λειτουργεί με διαχωρισμό οθόνης."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Συννεφάκι"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Διαχείριση"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Το συννεφάκι παραβλέφθηκε."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Πατήστε για επανεκκίνηση αυτής της εφαρμογής και ενεργοποίηση πλήρους οθόνης."</string>
+    <string name="got_it" msgid="4428750913636945527">"Το κατάλαβα"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 90c71c0..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <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="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 90c71c0..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <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="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 90c71c0..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <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="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 90c71c0..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <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="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index d8b5b40..87210d5 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎Skip to next‎‏‎‎‏‎"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎Skip to previous‎‏‎‎‏‎"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎Resize‎‏‎‎‏‎"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎Stash‎‏‎‎‏‎"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎Unstash‎‏‎‎‏‎"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎App may not work with split-screen.‎‏‎‎‏‎"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎App does not support split-screen.‎‏‎‎‏‎"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎App may not work on a secondary display.‎‏‎‎‏‎"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎Bubble‎‏‎‎‏‎"</string>
     <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="got_it" msgid="4428750913636945527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‎Got it‎‏‎‎‏‎"</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 7244b1a..ebe41e8 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Siguiente"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar el tamaño"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Almacenar de manera segura"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Dejar de almacenar de manera segura"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la app no funcione en el modo de pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La app no es compatible con la función de pantalla dividida."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string>
@@ -58,7 +60,7 @@
     <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Ubicar abajo a la derecha"</string>
     <string name="bubbles_app_settings" msgid="3617224938701566416">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Descartar burbuja"</string>
-    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar la conversación en burbujas"</string>
+    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar la conversación en burbuja"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat con burbujas"</string>
     <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla las burbujas"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Cuadro"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Entendido"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 65e75bd..5949099 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Saltar al siguiente"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Volver al anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"No esconder"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la aplicación no funcione con la pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La aplicación no admite la pantalla dividida."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string>
@@ -43,10 +45,10 @@
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
     <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior 30%"</string>
     <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
-    <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utilizar el modo una mano"</string>
+    <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usar Modo una mano"</string>
     <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación"</string>
-    <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo una mano"</string>
-    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Salir del modo una mano"</string>
+    <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar Modo una mano"</string>
+    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Salir del Modo una mano"</string>
     <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Ajustes de las burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú adicional"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Volver a añadir a la pila"</string>
@@ -60,7 +62,7 @@
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Cerrar burbuja"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar conversación en burbuja"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatea con burbujas"</string>
-    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca para abrir la burbuja. Arrastra para moverla."</string>
+    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca una burbuja para abrirla. Arrástrala para moverla."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla las burbujas"</string>
     <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Entendido"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 0ccfcfe..8330981 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Järgmise juurde"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Eelmise juurde"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Suuruse muutmine"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Pane hoidlasse"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Eemalda hoidlast"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Rakendus ei toeta jagatud ekraani."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Mull"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Selge"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 6682ea8..6649769 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -25,9 +25,11 @@
     <string name="pip_notification_message" msgid="8854051911700302620">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
     <string name="pip_play" msgid="3496151081459417097">"Erreproduzitu"</string>
     <string name="pip_pause" msgid="690688849510295232">"Pausatu"</string>
-    <string name="pip_skip_to_next" msgid="8403429188794867653">"Saltatu hurrengora"</string>
-    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Saltatu aurrekora"</string>
+    <string name="pip_skip_to_next" msgid="8403429188794867653">"Joan hurrengora"</string>
+    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Joan aurrekora"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Aldatu tamaina"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Gorde"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ez gorde"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikazioak ez du onartzen pantaila zatitua"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbuila"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Ados"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index a41811d..ca7d077 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"رد شدن به بعدی"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"رد شدن به قبلی"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغییر اندازه"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"مخفی‌سازی"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"لغو مخفی‌سازی"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن است برنامه با «صفحهٔ دونیمه» کار نکند."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"برنامه از تقسیم صفحه پشتیبانی نمی‌کند."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string>
@@ -62,11 +64,13 @@
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"گپ بااستفاده از حبابک‌ها"</string>
     <string name="bubbles_user_education_description" msgid="4215862563054175407">"مکالمه‌های جدید به‌صورت نمادهای شناور یا حبابک‌ها نشان داده می‌شوند. برای باز کردن حبابک‌ها ضربه بزنید. برای جابه‌جایی، آن را بکشید."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"کنترل حبابک‌ها در هرزمانی"</string>
-    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"برای خاموش کردن «حبابک‌ها» از این برنامه، روی «مدیریت» ضربه بزنید"</string>
+    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"برای خاموش کردن حبابک‌ها از این برنامه، روی «مدیریت» ضربه بزنید"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"متوجه‌ام"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"هیچ حبابک جدیدی وجود ندارد"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابک‌ها اخیر و حبابک‌ها ردشده اینجا ظاهر خواهند شد"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابک‌های اخیر و حبابک‌های ردشده اینجا ظاهر خواهند شد"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"حباب"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"برای بازراه‌اندازی این برنامه و تغییر به حالت تمام‌صفحه، ضربه بزنید."</string>
+    <string name="got_it" msgid="4428750913636945527">"متوجه‌ام"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index fcdc70f..5f87163 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Siirry seuraavaan"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Siirry edelliseen"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Muuta kokoa"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Lisää turvasäilytykseen"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poista turvasäilytyksestä"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Sovellus ei ehkä toimi jaetulla näytöllä."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Sovellus ei tue jaetun näytön tilaa."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Kupla"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index ed82237..68df591 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Passer au suivant"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Revenir au précédent"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ajouter à la réserve"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Retirer de la réserve"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index ad98b85..eecc9cb 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Passer au contenu suivant"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Passer au contenu précédent"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Application incompatible avec l\'écran partagé."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
@@ -61,7 +63,7 @@
     <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher la conversation dans une bulle"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatter en utilisant des bulles"</string>
     <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
-    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Contrôler les paramètres des bulles"</string>
+    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Contrôlez les bulles à tout moment"</string>
     <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Appuyez sur \"Gérer\" pour désactiver les bulles de cette application"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 529825e..3583caf 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Ir ao seguinte"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ir ao anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Non esconder"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Pode que a aplicación non funcione coa pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A aplicación non é compatible coa función de pantalla dividida."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbulla"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Entendido"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index ee23e1e9..e0654bd 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"આગલા પર જાઓ"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"પહેલાંના પર જાઓ"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"કદ બદલો"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"છુપાવો"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"બતાવો"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"વિભાજિત-સ્ક્રીન સાથે ઍપ કદાચ કામ ન કરે."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"બબલ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"મેનેજ કરો"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"બબલ છોડી દેવાયો."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"આ ઍપ ફરીથી ચાલુ કરવા માટે ટૅપ કરીને પૂર્ણ સ્ક્રીન કરો."</string>
+    <string name="got_it" msgid="4428750913636945527">"સમજાઈ ગયું"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 34c1c85..55a30f2 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"अगले पर जाएं"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"पिछले पर जाएं"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदलें"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"छिपाएं"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"दिखाएं"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ऐप्लिकेशन शायद स्प्लिट स्क्रीन मोड में काम न करे."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ऐप विभाजित स्‍क्रीन का समर्थन नहीं करता है."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string>
@@ -67,6 +69,8 @@
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
-    <string name="manage_bubbles_text" msgid="7730624269650594419">"प्रबंधित करें"</string>
+    <string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन पर देखने के लिए टैप करें."</string>
+    <string name="got_it" msgid="4428750913636945527">"ठीक है"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 32b21aa..f6acb5c 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na sljedeće"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prethodno"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sakrijte"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poništite sakrivanje"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podijeljeni zaslon."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Shvaćam"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 123b127..0c1c8a40 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Ugrás a következőre"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ugrás az előzőre"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Átméretezés"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Félretevés"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Félretevés megszüntetése"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Buborék"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Rendben"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index b047cf1..36204c1 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Անցնել հաջորդին"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Վերադառնալ նախորդին"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Փոխել չափը"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Թաքցնել"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ցուցադրել"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում։"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Պղպջակ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Հպեք՝ հավելվածը վերագործարկելու և լիաէկրան ռեժիմին անցնելու համար։"</string>
+    <string name="got_it" msgid="4428750913636945527">"Եղավ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index a75cdb4..de962c4 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Lewati ke berikutnya"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Lewati ke sebelumnya"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah ukuran"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Batalkan stash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App tidak mendukung layar terpisah."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Oke"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 3b28148..c205d22 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Fara á næsta"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Fara á fyrra"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Breyta stærð"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Geymsla"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Taka úr geymslu"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Hugsanlega virkar forritið ekki með skjáskiptingu."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Forritið styður ekki að skjánum sé skipt."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Blaðra"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Ég skil"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 8a2b9db..c788a03 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Passa ai contenuti successivi"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Passa ai contenuti precedenti"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ridimensiona"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Accantona"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Annulla accantonamento"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"L\'app potrebbe non funzionare con lo schermo diviso."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'app non supporta la modalità Schermo diviso."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string>
@@ -60,7 +62,7 @@
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignora bolla"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mettere la conversazione nella bolla"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatta utilizzando le bolle"</string>
-    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
+    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Le nuove conversazioni vengono mostrate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlla le bolle quando vuoi"</string>
     <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tocca Gestisci per disattivare le bolle dall\'app"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Fumetto"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 20114a7..b0c03ed 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -18,16 +18,18 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="pip_phone_close" msgid="5783752637260411309">"סגירה"</string>
-    <string name="pip_phone_expand" msgid="2579292903468287504">"הרחב"</string>
+    <string name="pip_phone_expand" msgid="2579292903468287504">"הרחבה"</string>
     <string name="pip_phone_settings" msgid="5468987116750491918">"הגדרות"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"תפריט"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
-    <string name="pip_notification_message" msgid="8854051911700302620">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש להקיש כדי לפתוח את ההגדרות ולכבות את התכונה."</string>
+    <string name="pip_notification_message" msgid="8854051911700302620">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש להקיש כדי לפתוח את ההגדרות ולהשבית את התכונה."</string>
     <string name="pip_play" msgid="3496151081459417097">"הפעלה"</string>
-    <string name="pip_pause" msgid="690688849510295232">"השהה"</string>
+    <string name="pip_pause" msgid="690688849510295232">"השהיה"</string>
     <string name="pip_skip_to_next" msgid="8403429188794867653">"אפשר לדלג אל הבא"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"אפשר לדלג אל הקודם"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"שינוי גודל"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"הסתרה זמנית"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ביטול ההסתרה הזמנית"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ייתכן שהאפליקציה לא תפעל במסך מפוצל."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"האפליקציה אינה תומכת במסך מפוצל."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
@@ -41,14 +43,14 @@
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"מסך עליון מלא"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"עליון 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string>
-    <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"עליון 30%"</string>
+    <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"למעלה 30%"</string>
     <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"מסך תחתון מלא"</string>
-    <string name="one_handed_tutorial_title" msgid="4583241688067426350">"איך להשתמש במצב שימוש ביד אחת"</string>
+    <string name="one_handed_tutorial_title" msgid="4583241688067426350">"איך להשתמש בתכונה \'מצב שימוש ביד אחת\'"</string>
     <string name="one_handed_tutorial_description" msgid="3486582858591353067">"כדי לצאת, יש להחליק למעלה מתחתית המסך או להקיש במקום כלשהו במסך מעל האפליקציה"</string>
     <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"הפעלה של מצב שימוש ביד אחת"</string>
     <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"יציאה ממצב שימוש ביד אחת"</string>
-    <string name="bubbles_settings_button_description" msgid="1301286017420516912">"הגדרות בשביל בועות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"גלישה"</string>
+    <string name="bubbles_settings_button_description" msgid="1301286017420516912">"הגדרות לבועות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"אפשרויות נוספות"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"הוספה בחזרה לערימה"</string>
     <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מהאפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
     <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מ-<xliff:g id="APP_NAME">%2$s</xliff:g> ועוד <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"בועה"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"צריך להקיש כדי להפעיל מחדש את האפליקציה הזו ולעבור למסך מלא."</string>
+    <string name="got_it" msgid="4428750913636945527">"הבנתי"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
index 8ca54e0..ef98a9c 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -19,6 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="notification_channel_tv_pip" msgid="2576686079160402435">"תמונה בתוך תמונה"</string>
     <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(תוכנית ללא כותרת)"</string>
-    <string name="pip_close" msgid="9135220303720555525">"‏סגור PIP"</string>
+    <string name="pip_close" msgid="9135220303720555525">"‏סגירת PIP"</string>
     <string name="pip_fullscreen" msgid="7278047353591302554">"מסך מלא"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index fbb2951..36700bd 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"次へスキップ"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"前へスキップ"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"サイズ変更"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"非表示"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"表示"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"アプリは分割画面では動作しないことがあります。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"アプリで分割画面がサポートされていません。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string>
@@ -61,7 +63,7 @@
     <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"会話をバブルで表示しない"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"チャットでバブルを使う"</string>
     <string name="bubbles_user_education_description" msgid="4215862563054175407">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
-    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"いつでもバブルを管理"</string>
+    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"バブルはいつでも管理可能"</string>
     <string name="bubbles_user_education_manage" msgid="3460756219946517198">"このアプリからのバブルを OFF にするには、[管理] をタップしてください"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近閉じたバブルはありません"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"バブル"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"タップしてこのアプリを再起動すると、全画面表示になります。"</string>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index f978481..af1377a 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"შემდეგზე გადასვლა"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"წინაზე გადასვლა"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ზომის შეცვლა"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"გადანახვა"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"გადანახვის გაუქმება"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ბუშტი"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"მართვა"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ბუშტი დაიხურა."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"შეეხეთ ამ აპის გადასატვირთად და გადადით სრულ ეკრანზე."</string>
+    <string name="got_it" msgid="4428750913636945527">"გასაგებია"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 2d27faf..6deb0b8 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Келесіге өту"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Алдыңғысына оралу"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлшемін өзгерту"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Жасыру"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Көрсету"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Қодланба бөлінген экранды қолдамайды."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string>
@@ -68,5 +70,7 @@
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Көпіршік"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
-    <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқымалы анықтама өшірілді."</string>
+    <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқыма хабар жабылды."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string>
+    <string name="got_it" msgid="4428750913636945527">"Түсінікті"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index d503b7a..c59d0fc 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"រំលងទៅបន្ទាប់"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"រំលងទៅក្រោយ"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ប្ដូរ​ទំហំ"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"លាក់ជាបណ្ដោះអាសន្ន"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ឈប់លាក់ជាបណ្ដោះអាសន្ន"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"កម្មវិធី​អាចនឹងមិន​ដំណើរការ​ជាមួយ​មុខងារបំបែកអេក្រង់​ទេ។"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះ​ប្រហែល​ជាមិនដំណើរការ​នៅលើ​អេក្រង់បន្ទាប់បន្សំទេ។"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ពពុះ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"គ្រប់គ្រង"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"បានច្រានចោល​សារលេចឡើង។"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ចុចដើម្បី​ចាប់ផ្ដើម​កម្មវិធី​នេះឡើងវិញ រួចចូលប្រើ​ពេញអេក្រង់។"</string>
+    <string name="got_it" msgid="4428750913636945527">"យល់ហើយ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 3d61d84..5e655b4 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ಮುಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ಹಿಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ಅನ್‌ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ವಿಭಜಿಸಿದ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್‌ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ಬಬಲ್"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ನಿರ್ವಹಿಸಿ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="got_it" msgid="4428750913636945527">"ಅರ್ಥವಾಯಿತು"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index ea7ad56..af34ef4 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"다음으로 건너뛰기"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"이전으로 건너뛰기"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"크기 조절"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"숨기기"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"숨기기 취소"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"앱이 화면 분할을 지원하지 않습니다."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"탭하여 이 앱을 다시 시작하고 전체 화면으로 이동합니다."</string>
+    <string name="got_it" msgid="4428750913636945527">"확인"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 611b2d6..c16041d 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Кийинкисине өткөрүп жиберүү"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Мурункусуна өткөрүп жиберүү"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлчөмүн өзгөртүү"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сейфке салуу"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Сейфтен чыгаруу"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Колдонмодо экран бөлүнбөйт."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string>
@@ -62,11 +64,13 @@
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
     <string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
-    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн, \"Башкарууну\" басыңыз"</string>
+    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн \"Башкарууну\" басыңыз"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Түшүндүм"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Азырынча эч нерсе жок"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Көбүк"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Башкаруу"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Калкып чыкма билдирме жабылды."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Бул колдонмону өчүрүп күйгүзүп, толук экранга өтүү үчүн таптап коюңуз."</string>
+    <string name="got_it" msgid="4428750913636945527">"Түшүндүм"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index a1c998c..a578b0a 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ຂ້າມໄປລາຍການໜ້າ"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ຂ້າມໄປລາຍການກ່ອນນີ້"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ປ່ຽນຂະໜາດ"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ເກັບໄວ້ບ່ອນເກັບສ່ວນຕົວ"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ເອົາອອກຈາກບ່ອນເກັບສ່ວນຕົວ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ຟອງ"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"ເຂົ້າໃຈແລ້ວ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index b2ccd57..e037839 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Praleisti ir eiti į kitą"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Praleisti ir eiti į ankstesnį"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Pakeisti dydį"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslėpti"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Nebeslėpti"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Programa gali neveikti naudojant išskaidyto ekrano režimą."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programoje nepalaikomas skaidytas ekranas."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Debesėlis"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Supratau"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index e6d0c77..05472e4 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Pāriet uz nākamo"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pāriet uz iepriekšējo"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Mainīt lielumu"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslēpt"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Rādīt"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Iespējams, lietotne nedarbosies ekrāna sadalīšanas režīmā."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbulis"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Labi"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 43f2881..9cb2c69 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Прескокни до следната"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Прескокни до претходната"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промени големина"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сокријте"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Прикажете"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликацијата може да не работи со поделен екран."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликацијата не поддржува поделен екран."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Допрете за да ја рестартирате апликацијава и да ја отворите на цел екран."</string>
+    <string name="got_it" msgid="4428750913636945527">"Сфатив"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index e675861..f0bf513 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"അടുത്തതിലേക്ക് പോകുക"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"മുമ്പത്തേതിലേക്ക് പോകുക"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"വലുപ്പം മാറ്റുക"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"സ്റ്റാഷ് ചെയ്യൽ"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"അൺസ്റ്റാഷ് ചെയ്യൽ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"സ്‌ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്‌പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
@@ -66,7 +68,9 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"മനസ്സിലായി"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
-    <string name="notification_bubble_title" msgid="6082910224488253378">"ബബ്ൾ"</string>
+    <string name="notification_bubble_title" msgid="6082910224488253378">"ബബിൾ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"മാനേജ് ചെയ്യുക"</string>
-    <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബ്ൾ ഡിസ്മിസ് ചെയ്തു."</string>
+    <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബിൾ ഡിസ്മിസ് ചെയ്തു."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ഈ ആപ്പ് റീസ്‌റ്റാർട്ട് ചെയ്‌ത് പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറാൻ ടാപ്പ് ചെയ്യുക."</string>
+    <string name="got_it" msgid="4428750913636945527">"മനസ്സിലായി"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 044fd9f..68822cb 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Дараагийн медиад очих"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Өмнөх медиад очих"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Хэмжээг өөрчлөх"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Нуух"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ил гаргах"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Апп хуваагдсан дэлгэц дээр ажиллахгүй байж болзошгүй."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Бөмбөлөг"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Удирдах"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Бөмбөлгийг үл хэрэгссэн."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Энэ аппыг дахин эхлүүлж, бүтэн дэлгэцэд орохын тулд товшино уу."</string>
+    <string name="got_it" msgid="4428750913636945527">"Ойлголоо"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index e838cf5..a4b7be4 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"डावलून पुढे जा"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"डावलून मागे जा"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदला"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्टॅश करा"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्टॅश करा"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"अ‍ॅप कदाचित स्प्लिट स्क्रीनसह काम करू शकत नाही."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अ‍ॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"दुसऱ्या डिस्प्लेवर अ‍ॅप कदाचित चालणार नाही."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापित करा"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल डिसमिस केला."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"हे अ‍ॅप रीस्टार्ट करण्यासाठी आणि फुल स्क्रीन करण्यासाठी टॅप करा."</string>
+    <string name="got_it" msgid="4428750913636945527">"समजले"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 6664f38..2f33bfa 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Langkau ke seterusnya"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Langkau ke sebelumnya"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah saiz"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sembunyikan"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Tunjukkan"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Apl tidak menyokong skrin pisah."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Gelembung"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 9681d14..018ffc0 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"နောက်တစ်ခုသို့ ကျော်ရန်"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ယခင်တစ်ခုသို့ ပြန်သွားရန်"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"အရွယ်အစားပြောင်းရန်"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"သိုဝှက်ရန်"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"မသိုဝှက်ရန်"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းဖြင့် အက်ပ်သည် အလုပ်မလုပ်ပါ။"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ပူဖောင်းဖောက်သံ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"စီမံရန်"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ဤအက်ပ်ကို ပြန်စပြီး ဖန်သားပြင်အပြည့်လုပ်ရန် တို့ပါ။"</string>
+    <string name="got_it" msgid="4428750913636945527">"ရပြီ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 986e890..a23ad90 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Hopp til neste"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Hopp til forrige"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Endre størrelse"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Oppbevar"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Avslutt oppbevaring"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen støtter ikke delt skjerm."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Greit"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 0369c6d..5b9b872 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -28,9 +28,11 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"अर्कोमा जानुहोस्"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"अघिल्लोमा जानुहोस्"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदल्नुहोस्"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्ट्यास गर्नुहोस्"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्ट्यास गर्नुहोस्"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
-    <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो अनुप्रयोगले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
+    <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string>
     <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बायाँ भाग फुल स्क्रिन"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापन गर्नुहोस्"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल हटाइयो।"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"यो एप रिस्टार्ट गर्न ट्याप गर्नुहोस् र फुल स्क्रिन मोडमा जानुहोस्।"</string>
+    <string name="got_it" msgid="4428750913636945527">"बुझेँ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 26c276e..69fc25a 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -22,12 +22,14 @@
     <string name="pip_phone_settings" msgid="5468987116750491918">"Instellingen"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
-    <string name="pip_notification_message" msgid="8854051911700302620">"Als je niet wilt dat <xliff:g id="NAME">%s</xliff:g> deze functie gebruikt, tik je om de instellingen te openen en schakel je de functie uit."</string>
+    <string name="pip_notification_message" msgid="8854051911700302620">"Als je niet wilt dat <xliff:g id="NAME">%s</xliff:g> deze functie gebruikt, tik je om de instellingen te openen en zet je de functie uit."</string>
     <string name="pip_play" msgid="3496151081459417097">"Afspelen"</string>
     <string name="pip_pause" msgid="690688849510295232">"Onderbreken"</string>
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Doorgaan naar volgende"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Teruggaan naar vorige"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Formaat aanpassen"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Verbergen"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Niet meer verbergen"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"De app werkt mogelijk niet met gesplitst scherm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App biedt geen ondersteuning voor gesplitst scherm."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string>
@@ -58,15 +60,17 @@
     <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Naar rechtsonder verplaatsen"</string>
     <string name="bubbles_app_settings" msgid="3617224938701566416">"Instellingen voor <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Bubbel sluiten"</string>
-    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Gesprekken niet in bubbels weergeven"</string>
+    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Gesprekken niet in bubbels tonen"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatten met bubbels"</string>
-    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nieuwe gesprekken worden weergegeven als zwevende iconen of \'bubbels\'. Tik om een bubbel te openen. Sleep om de bubbel te verplaatsen."</string>
+    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nieuwe gesprekken worden als zwevende iconen of bubbels getoond. Tik om een bubbel te openen. Sleep om een bubbel te verplaatsen."</string>
     <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Beheer bubbels wanneer je wilt"</string>
-    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tik op Beheren om bubbels van deze app uit te schakelen"</string>
+    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tik op Beheren om bubbels van deze app uit te zetten"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen recente bubbels"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recente bubbels en gesloten bubbels worden hier weergegeven"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recente bubbels en gesloten bubbels zie je hier"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubbel"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 27f1622..ac1e84a 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ପରବର୍ତ୍ତୀକୁ ଯାଆନ୍ତୁ"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ପୂର୍ବବର୍ତ୍ତୀକୁ ଛାଡ଼ନ୍ତୁ"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ରିସାଇଜ୍ କରନ୍ତୁ"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ଲୁଚାନ୍ତୁ"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ଦେଖାନ୍ତୁ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରିନରେ ଆପ୍ କାମ କରିନପାରେ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ଆପ୍‍ ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ କାମ ନକରିପାରେ।"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ବବଲ୍"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ଏହି ଆପକୁ ରିଷ୍ଟାର୍ଟ କରି ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+    <string name="got_it" msgid="4428750913636945527">"ବୁଝିଗଲି"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 96688b9..bf5b733c 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ਅਗਲੇ \'ਤੇ ਜਾਓ"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ਪਿਛਲੇ \'ਤੇ ਜਾਓ"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ਆਕਾਰ ਬਦਲੋ"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ਸਟੈਸ਼"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ਅਣਸਟੈਸ਼"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"ਬੁਲਬੁਲਾ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਪੂਰੀ ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਓ।"</string>
+    <string name="got_it" msgid="4428750913636945527">"ਸਮਝ ਲਿਆ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 6b640b5..cd659ba 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Dalej"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Wstecz"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmień rozmiar"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Przenieś do schowka"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zabierz ze schowka"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacja może nie działać przy podzielonym ekranie."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacja nie obsługuje dzielonego ekranu."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacja może nie działać na dodatkowym ekranie."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Dymek"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 465d2d1..9c97ffe 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Pular para a próxima"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pular para a anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ocultar"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Ok"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index df841bf..1f5b0ab 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Mudar para o seguinte"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Mudar para o anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Armazenar"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do armazenamento"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"A app pode não funcionar com o ecrã dividido."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A app não é compatível com o ecrã dividido."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"A app pode não funcionar num ecrã secundário."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 465d2d1..9c97ffe 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Pular para a próxima"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pular para a anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ocultar"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Ok"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 55a4376..d694be1 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Treceți la următorul"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Treceți la cel anterior"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionați"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stocați"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulați stocarea"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 8ae00d2..e9bfffb 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Перейти к следующему"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Перейти к предыдущему"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Изменить размер"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Скрыть"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показать"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"В режиме разделения экрана приложение может работать нестабильно."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложение не поддерживает разделение экрана."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Приложение может не работать на дополнительном экране"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Всплывающая подсказка"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Настроить"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Всплывающий чат закрыт."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Нажмите, чтобы перезапустить приложение и перейти в полноэкранный режим."</string>
+    <string name="got_it" msgid="4428750913636945527">"ОК"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 081926f..ba178f0 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ඊළඟ එකට පනින්න"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"පෙර එකට පනින්න"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ප්‍රතිප්‍රමාණ කරන්න"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"සඟවා තබන්න"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"සඟවා තැබීම ඉවත් කරන්න"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"යෙදුම බෙදුම් තිරය සමග ක්‍රියා නොකළ හැකිය"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"යෙදුම ද්විතියික සංදර්ශකයක ක්‍රියා නොකළ හැකිය."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"බුබුළු"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"කළමනා කරන්න"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"බුබුල ඉවත දමා ඇත."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"මෙම යෙදුම යළි ඇරඹීමට සහ පූර්ණ තිරයට යාමට තට්ටු කරන්න."</string>
+    <string name="got_it" msgid="4428750913636945527">"තේරුණා"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 24fded7..e048ca1 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskočiť na ďalšie"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskočiť na predchádzajúce"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmeniť veľkosť"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skryť"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušiť skrytie"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikácia nemusí fungovať s rozdelenou obrazovkou."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikácia nemusí fungovať na sekundárnej obrazovke."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Dobre"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 3f42530..ed05908 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na naslednjega"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prejšnjega"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Spremeni velikost"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Zakrij"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Razkrij"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija morda ne bo delovala na sekundarnem zaslonu."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Mehurček"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Razumem"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index ddae724..13e830c 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Kalo te tjetra"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Kalo tek e mëparshmja"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ndrysho përmasat"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Fshih"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Mos e fshih"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacioni mund të mos funksionojë në një ekran dytësor."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Flluskë"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"E kuptova"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 74c9ac0..be6857b 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Пређи на следеће"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Пређи на претходно"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промените величину"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ставите у тајну меморију"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Уклоните из тајне меморије"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликација можда неће радити са подељеним екраном."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликација не подржава подељени екран."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликација можда неће функционисати на секундарном екрану."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Облачић"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управљајте"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Облачић је одбачен."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Додирните да бисте рестартовали апликацију и прешли у режим целог екрана."</string>
+    <string name="got_it" msgid="4428750913636945527">"Важи"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 81328a8..e61e69b 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Hoppa till nästa"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Hoppa till föregående"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ändra storlek"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Utför stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Återställ stash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen kanske inte fungerar med delad skärm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen har inte stöd för delad skärm."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen kanske inte fungerar på en sekundär skärm."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubbla"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 4559832..476af11 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Ruka ufikie inayofuata"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ruka ufikie iliyotangulia"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Badilisha ukubwa"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ficha"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Fichua"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Huenda programu isifanye kazi kwenye dirisha lingine."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Kiputo"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Nimeelewa"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 586ee94..bc27389 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"அடுத்ததற்குச் செல்"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"முந்தையதற்குச் செல்"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"அளவு மாற்று"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"திரைப் பிரிப்பு அம்சத்தில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"பபிள்"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கலாம், முழுத்திரையில் பார்க்கலாம்."</string>
+    <string name="got_it" msgid="4428750913636945527">"சரி"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 4e85b43..624b8b3 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"దాటవేసి తర్వాత దానికి వెళ్లు"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"దాటవేసి మునుపటి దానికి వెళ్లు"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"పరిమాణం మార్చు"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"బబుల్"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"మేనేజ్ చేయండి"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"బబుల్ విస్మరించబడింది."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"ఈ యాప్‌ను రీస్టార్ట్ చేయడానికి ట్యాప్ చేసి, ఆపై పూర్తి స్క్రీన్‌లోకి వెళ్లండి."</string>
+    <string name="got_it" msgid="4428750913636945527">"అర్థమైంది"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 66c7018..9017b3f 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"ข้ามไปรายการถัดไป"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"ข้ามไปรายการก่อนหน้า"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ปรับขนาด"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"เก็บเข้าที่เก็บส่วนตัว"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"เอาออกจากที่เก็บส่วนตัว"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"แอปอาจใช้ไม่ได้กับโหมดแบ่งหน้าจอ"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"แอปอาจไม่ทำงานในจอแสดงผลรอง"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"บับเบิล"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"จัดการ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ปิดบับเบิลแล้ว"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"แตะเพื่อรีสตาร์ทแอปนี้และแสดงแบบเต็มหน้าจอ"</string>
+    <string name="got_it" msgid="4428750913636945527">"รับทราบ"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index a76bf6f..c484caf 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Lumaktaw sa susunod"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Lumaktaw sa nakaraan"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"I-resize"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"I-stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"I-unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Posibleng hindi gumana ang app sa split screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Hindi sinusuportahan ng app ang split-screen."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Maaaring hindi gumana ang app sa pangalawang display."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index b3276da..ca856a1 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Sonrakine atla"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Öncekine atla"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Yeniden boyutlandır"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Depola"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Depolama"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Uygulama bölünmüş ekranda çalışmayabilir."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uygulama bölünmüş ekranı desteklemiyor."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uygulama ikincil ekranda çalışmayabilir."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Baloncuk"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Anladım"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 8e303cf..08e8d29 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Перейти далі"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Перейти назад"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змінити розмір"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сховати"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показати"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Додаток може не працювати в режимі розділеного екрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Додаток не підтримує розділення екрана."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Додаток може не працювати на додатковому екрані."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Спливаюче сповіщення"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Налаштувати"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Спливаюче сповіщення закрито."</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"Натисніть, щоб перезапустити додаток і перейти в повноекранний режим."</string>
+    <string name="got_it" msgid="4428750913636945527">"Зрозуміло"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 4b0adc6..06c0927 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"نظرانداز کرکے اگلے پر جائیں"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"نظرانداز کرکے پچھلے پر جائیں"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"سائز تبدیل کریں"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن ہے کہ ایپ اسپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"بلبلہ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"نظم کریں"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"بلبلہ برخاست کر دیا گیا۔"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"یہ ایپ دوبارہ شروع کرنے کے لیے تھپتھپائیں اور پوری اسکرین پر جائیں۔"</string>
+    <string name="got_it" msgid="4428750913636945527">"سمجھ آ گئی"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 74b135d..6a873a3 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Keyingisiga o‘tish"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Avvalgisiga qaytish"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Oʻlchamini oʻzgartirish"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Berkitish"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Chiqarish"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Bu ilova ekranni ikkiga ajratish rejimini dastaklamaydi."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Bu ilova qo‘shimcha ekranda ishlamasligi mumkin."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Pufaklar"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"OK"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index ce37231..4d4eebc 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Chuyển tới mục tiếp theo"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Chuyển về mục trước"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Đổi kích thước"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ẩn"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Hiện"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Tôi hiểu"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 3143130..3b8c889 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一个"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一个"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"调整大小"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"隐藏"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消隐藏"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"应用可能无法在分屏模式下正常运行。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"应用不支持分屏。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"应用可能无法在辅显示屏上正常运行。"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"气泡"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭对话泡。"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"点按即可重启此应用并进入全屏模式。"</string>
+    <string name="got_it" msgid="4428750913636945527">"知道了"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 4f8bfe0..9ba82b5 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一個"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"保護"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消保護"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"應用程式不支援分割畫面。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示屏上運作。"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"氣泡"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"對話氣泡已關閉。"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"輕按即可重新開啟此應用程式並放大至全螢幕。"</string>
+    <string name="got_it" msgid="4428750913636945527">"知道了"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 6fb8ed9..0af8d24 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一個"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"暫時隱藏"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消暫時隱藏"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"這個應用程式不支援分割畫面。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示器上運作。"</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"泡泡"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
+    <string name="restart_button_description" msgid="5887656107651190519">"輕觸即可重新啟動這個應用程式並進入全螢幕模式。"</string>
+    <string name="got_it" msgid="4428750913636945527">"我知道了"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index cab2776..c8199c8 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -28,6 +28,8 @@
     <string name="pip_skip_to_next" msgid="8403429188794867653">"Yeqela kokulandelayo"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"Yeqela kokwangaphambilini"</string>
     <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Shintsha usayizi"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Yenza isiteshi"</string>
+    <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Susa isiteshi"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili."</string>
@@ -69,4 +71,6 @@
     <string name="notification_bubble_title" msgid="6082910224488253378">"Ibhamuza"</string>
     <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>
+    <string name="got_it" msgid="4428750913636945527">"Ngiyezwa"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index 34c66a4..bf074b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -97,6 +97,14 @@
         b.setParent(sc);
     }
 
+    public void setPosition(@NonNull SurfaceControl.Transaction tx, int displayId, int x, int y) {
+        final SurfaceControl sc = mLeashes.get(displayId);
+        if (sc == null) {
+            throw new IllegalArgumentException("can't find display" + displayId);
+        }
+        tx.setPosition(sc, x, y);
+    }
+
     @Override
     public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
             @NonNull SurfaceControl leash) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 1861e48..2f3214d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -40,6 +40,8 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import com.android.wm.shell.common.SyncTransactionQueue;
+
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
 
@@ -74,6 +76,7 @@
 
     private final ShellTaskOrganizer mTaskOrganizer;
     private final Executor mShellExecutor;
+    private final SyncTransactionQueue mSyncQueue;
 
     private ActivityManager.RunningTaskInfo mTaskInfo;
     private WindowContainerToken mTaskToken;
@@ -89,11 +92,12 @@
     private final Rect mTmpRootRect = new Rect();
     private final int[] mTmpLocation = new int[2];
 
-    public TaskView(Context context, ShellTaskOrganizer organizer) {
+    public TaskView(Context context, ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue) {
         super(context, null, 0, 0, true /* disableBackgroundLayer */);
 
         mTaskOrganizer = organizer;
         mShellExecutor = organizer.getExecutor();
+        mSyncQueue = syncQueue;
         setUseAlpha();
         getHolder().addCallback(this);
         mGuard.open("release");
@@ -189,8 +193,7 @@
 
         WindowContainerTransaction wct = new WindowContainerTransaction();
         wct.setBounds(mTaskToken, mTmpRect);
-        // TODO(b/151449487): Enable synchronization
-        mTaskOrganizer.applyTransaction(wct);
+        mSyncQueue.queue(wct);
     }
 
     /**
@@ -236,14 +239,16 @@
     private void updateTaskVisibility() {
         WindowContainerTransaction wct = new WindowContainerTransaction();
         wct.setHidden(mTaskToken, !mSurfaceCreated /* hidden */);
-        mTaskOrganizer.applyTransaction(wct);
-        // TODO(b/151449487): Only call callback once we enable synchronization
-        if (mListener != null) {
-            final int taskId = mTaskInfo.taskId;
+        mSyncQueue.queue(wct);
+        if (mListener == null) {
+            return;
+        }
+        int taskId = mTaskInfo.taskId;
+        mSyncQueue.runInSync((t) -> {
             mListenerExecutor.execute(() -> {
                 mListener.onTaskVisibilityChanged(taskId, mSurfaceCreated);
             });
-        }
+        });
     }
 
     @Override
@@ -264,10 +269,12 @@
             updateTaskVisibility();
         }
         mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true);
-        // TODO: Synchronize show with the resize
         onLocationChanged();
         if (taskInfo.taskDescription != null) {
-            setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+            int backgroundColor = taskInfo.taskDescription.getBackgroundColor();
+            mSyncQueue.runInSync((t) -> {
+                setResizeBackgroundColor(t, backgroundColor);
+            });
         }
 
         if (mListener != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java
index 58ca1fb..8286d10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskViewFactoryController.java
@@ -20,8 +20,8 @@
 import android.content.Context;
 
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.common.annotations.ShellMainThread;
 
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -30,12 +30,14 @@
 public class TaskViewFactoryController {
     private final ShellTaskOrganizer mTaskOrganizer;
     private final ShellExecutor mShellExecutor;
+    private final SyncTransactionQueue mSyncQueue;
     private final TaskViewFactory mImpl = new TaskViewFactoryImpl();
 
     public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer,
-            ShellExecutor shellExecutor) {
+            ShellExecutor shellExecutor, SyncTransactionQueue syncQueue) {
         mTaskOrganizer = taskOrganizer;
         mShellExecutor = shellExecutor;
+        mSyncQueue = syncQueue;
     }
 
     public TaskViewFactory asTaskViewFactory() {
@@ -44,7 +46,7 @@
 
     /** Creates an {@link TaskView} */
     public void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate) {
-        TaskView taskView = new TaskView(context, mTaskOrganizer);
+        TaskView taskView = new TaskView(context, mTaskOrganizer, mSyncQueue);
         executor.execute(() -> {
             onCreate.accept(taskView);
         });
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 09fcb86..f3f66dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -85,6 +85,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
@@ -137,6 +138,7 @@
     private final TaskStackListenerImpl mTaskStackListener;
     private final ShellTaskOrganizer mTaskOrganizer;
     private final DisplayController mDisplayController;
+    private final SyncTransactionQueue mSyncQueue;
 
     // Used to post to main UI thread
     private final ShellExecutor mMainExecutor;
@@ -209,7 +211,8 @@
             ShellTaskOrganizer organizer,
             DisplayController displayController,
             ShellExecutor mainExecutor,
-            Handler mainHandler) {
+            Handler mainHandler,
+            SyncTransactionQueue syncQueue) {
         BubbleLogger logger = new BubbleLogger(uiEventLogger);
         BubblePositioner positioner = new BubblePositioner(context, windowManager);
         BubbleData data = new BubbleData(context, logger, positioner, mainExecutor);
@@ -217,7 +220,7 @@
                 new BubbleDataRepository(context, launcherApps, mainExecutor),
                 statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
                 logger, taskStackListener, organizer, positioner, displayController, mainExecutor,
-                mainHandler);
+                mainHandler, syncQueue);
     }
 
     /**
@@ -239,7 +242,8 @@
             BubblePositioner positioner,
             DisplayController displayController,
             ShellExecutor mainExecutor,
-            Handler mainHandler) {
+            Handler mainHandler,
+            SyncTransactionQueue syncQueue) {
         mContext = context;
         mLauncherApps = launcherApps;
         mBarService = statusBarService == null
@@ -262,6 +266,7 @@
         mSavedBubbleKeysPerUser = new SparseSetArray<>();
         mBubbleIconFactory = new BubbleIconFactory(context);
         mDisplayController = displayController;
+        mSyncQueue = syncQueue;
     }
 
     public void initialize() {
@@ -561,6 +566,10 @@
         return mTaskOrganizer;
     }
 
+    SyncTransactionQueue getSyncTransactionQueue() {
+        return mSyncQueue;
+    }
+
     /** Contains information to help position things on the screen.  */
     BubblePositioner getPositioner() {
         return mBubblePositioner;
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 9687ec6..a02fa9b 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
@@ -25,6 +25,7 @@
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT;
 
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
@@ -60,7 +61,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.launcher3.icons.IconNormalizer;
 import com.android.wm.shell.R;
 import com.android.wm.shell.TaskView;
 import com.android.wm.shell.common.AlphaOptimizedButton;
@@ -77,7 +77,6 @@
 
     // The triangle pointing to the expanded view
     private View mPointerView;
-    private int mPointerMargin;
     @Nullable private int[] mExpandedViewContainerLocation;
 
     private AlphaOptimizedButton mManageButton;
@@ -102,9 +101,6 @@
      */
     private boolean mIsAlphaAnimating = false;
 
-    private int mMinHeight;
-    private int mOverflowHeight;
-    private int mManageButtonHeight;
     private int mPointerWidth;
     private int mPointerHeight;
     private float mPointerRadius;
@@ -338,7 +334,8 @@
             bringChildToFront(mOverflowView);
             mManageButton.setVisibility(GONE);
         } else {
-            mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
+            mTaskView = new TaskView(mContext, mController.getTaskOrganizer(),
+                    mController.getSyncTransactionQueue());
             mTaskView.setListener(mController.getMainExecutor(), mTaskViewListener);
             mExpandedViewContainer.addView(mTaskView);
             bringChildToFront(mTaskView);
@@ -347,12 +344,8 @@
 
     void updateDimensions() {
         Resources res = getResources();
-        mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
-        mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
-
         updateFontSize();
 
-        mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
         mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
         mPointerRadius = getResources().getDimensionPixelSize(R.dimen.bubble_pointer_radius);
@@ -368,7 +361,6 @@
             updatePointerView();
         }
 
-        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
         if (mManageButton != null) {
             int visibility = mManageButton.getVisibility();
             removeView(mManageButton);
@@ -632,12 +624,11 @@
         }
 
         if ((mBubble != null && mTaskView != null) || mIsOverflow) {
-            float desiredHeight = mIsOverflow
-                    ? mPositioner.isLargeScreen() ? getMaxExpandedHeight() : mOverflowHeight
-                    : mBubble.getDesiredHeight(mContext);
-            desiredHeight = Math.max(desiredHeight, mMinHeight);
-            float height = Math.min(desiredHeight, getMaxExpandedHeight());
-            height = Math.max(height, mMinHeight);
+            float desiredHeight = mPositioner.getExpandedViewHeight(mBubble);
+            int maxHeight = mPositioner.getMaxExpandedViewHeight(mIsOverflow);
+            float height = desiredHeight == MAX_HEIGHT
+                    ? maxHeight
+                    : Math.min(desiredHeight, maxHeight);
             FrameLayout.LayoutParams lp = mIsOverflow
                     ? (FrameLayout.LayoutParams) mOverflowView.getLayoutParams()
                     : (FrameLayout.LayoutParams) mTaskView.getLayoutParams();
@@ -661,23 +652,6 @@
         }
     }
 
-    private int getMaxExpandedHeight() {
-        int expandedContainerY = mExpandedViewContainerLocation != null
-                // Remove top insets back here because availableRect.height would account for that
-                ? mExpandedViewContainerLocation[1] - mPositioner.getInsets().top
-                : 0;
-        int settingsHeight = mIsOverflow ? 0 : mManageButtonHeight;
-        int pointerHeight = mPositioner.showBubblesVertically()
-                ? mPointerWidth
-                : (int) (mPointerHeight - mPointerOverlap + mPointerMargin);
-        return mPositioner.getAvailableRect().height()
-                - expandedContainerY
-                - getPaddingTop()
-                - getPaddingBottom()
-                - settingsHeight
-                - pointerHeight;
-    }
-
     /**
      * Update appearance of the expanded view being displayed.
      *
@@ -727,14 +701,11 @@
                 : mPointerHeight - mPointerOverlap;
         setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0);
 
-        final float expandedViewY = mPositioner.getExpandedViewY();
-        // TODO: I don't understand why it works but it does - why normalized in portrait
-        //  & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation?
-        final float normalizedSize = IconNormalizer.getNormalizedCircleSize(
-                mPositioner.getBubbleSize());
-        final float bubbleCenter = showVertically
-                ? bubblePosition + (mPositioner.getBubbleSize() / 2f) - expandedViewY
-                : bubblePosition + (normalizedSize / 2f) - mPointerWidth;
+        // Subtract the expandedViewY here because the pointer is placed within the expandedView.
+        float pointerPosition = mPositioner.getPointerPosition(bubblePosition);
+        final float bubbleCenter = mPositioner.showBubblesVertically()
+                ? pointerPosition - mPositioner.getExpandedViewY(mBubble, bubblePosition)
+                : pointerPosition;
         // Post because we need the width of the view
         post(() -> {
             float pointerY;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index c600f56..0a856a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -34,6 +34,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.icons.IconNormalizer;
 import com.android.wm.shell.R;
 
 import java.lang.annotation.Retention;
@@ -58,6 +59,8 @@
 
     /** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/
     public static final int NUM_VISIBLE_WHEN_RESTING = 2;
+    /** Indicates a bubble's height should be the maximum available space. **/
+    public static final int MAX_HEIGHT = -1;
 
     private Context mContext;
     private WindowManager mWindowManager;
@@ -68,13 +71,16 @@
     private int mMaxBubbles;
 
     private int mBubbleSize;
-    private int mBubbleBadgeSize;
     private int mSpacingBetweenBubbles;
     private int mExpandedViewLargeScreenWidth;
     private int mExpandedViewPadding;
     private int mPointerMargin;
-    private float mPointerWidth;
-    private float mPointerHeight;
+    private int mPointerWidth;
+    private int mPointerHeight;
+    private int mPointerOverlap;
+    private int mManageButtonHeight;
+    private int mExpandedViewMinHeight;
+    private int mOverflowHeight;
 
     private PointF mPinLocation;
     private PointF mRestingStackPosition;
@@ -151,7 +157,6 @@
 
         Resources res = mContext.getResources();
         mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
-        mBubbleBadgeSize = res.getDimensionPixelSize(R.dimen.bubble_badge_size);
         mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
         mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
 
@@ -161,6 +166,10 @@
         mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
         mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
+        mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
+        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+        mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
+        mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
 
         mMaxBubbles = calculateMaxBubbles();
 
@@ -296,8 +305,8 @@
         return mPaddings;
     }
 
-    /** Calculates the y position of the expanded view when it is expanded. */
-    public float getExpandedViewY() {
+    /** Gets the y position of the expanded view if it was top-aligned. */
+    private float getExpandedViewYTopAligned() {
         final int top = getAvailableRect().top;
         if (showBubblesVertically()) {
             return top - mPointerWidth;
@@ -306,6 +315,116 @@
         }
     }
 
+    /** The maximum height the expanded view can be. */
+    public int getMaxExpandedViewHeight(boolean isOverflow) {
+        int paddingTop = showBubblesVertically()
+                ? 0
+                : mPointerHeight;
+        int settingsHeight = isOverflow ? 0 : mManageButtonHeight;
+        // Subtract pointer size because it's laid out in LinearLayout with the expanded view.
+        int pointerSize = showBubblesVertically()
+                ? mPointerWidth
+                : (mPointerHeight + mPointerMargin);
+        // Subtract top insets because availableRect.height would account for that
+        int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
+        return getAvailableRect().height()
+                - expandedContainerY
+                - paddingTop
+                - settingsHeight
+                - pointerSize;
+    }
+
+    /**
+     * Determines the height for the bubble, ensuring a minimum height. If the height should be as
+     * big as available, returns {@link #MAX_HEIGHT}.
+     */
+    public float getExpandedViewHeight(BubbleViewProvider bubble) {
+        boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
+        float desiredHeight = isOverflow
+                ? mOverflowHeight
+                : ((Bubble) bubble).getDesiredHeight(mContext);
+        int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
+        desiredHeight = Math.max(manageButtonHeight + desiredHeight, mExpandedViewMinHeight);
+        if (desiredHeight > getMaxExpandedViewHeight(isOverflow)) {
+            return MAX_HEIGHT;
+        }
+        return desiredHeight;
+    }
+
+    /**
+     * Gets the y position for the expanded view. This is the position on screen of the top
+     * horizontal line of the expanded view.
+     *
+     * @param bubble the bubble being positioned.
+     * @param bubblePosition the x position of the bubble if showing on top, the y position of the
+     *                       bubble if showing vertically.
+     * @return the y position for the expanded view.
+     */
+    public float getExpandedViewY(BubbleViewProvider bubble, float bubblePosition) {
+        boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
+        float expandedViewHeight = getExpandedViewHeight(bubble);
+        float topAlignment = getExpandedViewYTopAligned();
+        if (!showBubblesVertically() || expandedViewHeight == MAX_HEIGHT) {
+            // Top-align when bubbles are shown at the top or are max size.
+            return topAlignment;
+        }
+        // If we're here, we're showing vertically & developer has made height less than maximum.
+        int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
+        float pointerPosition = getPointerPosition(bubblePosition);
+        float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
+        float topIfCentered = pointerPosition - (expandedViewHeight / 2);
+        if (topIfCentered > mPositionRect.top && mPositionRect.bottom > bottomIfCentered) {
+            // Center it
+            return pointerPosition - mPointerWidth - (expandedViewHeight / 2f);
+        } else if (topIfCentered <= mPositionRect.top) {
+            // Top align
+            return topAlignment;
+        } else {
+            // Bottom align
+            return mPositionRect.bottom - manageButtonHeight - expandedViewHeight - mPointerWidth;
+        }
+    }
+
+    /**
+     * The position the pointer points to, the center of the bubble.
+     *
+     * @param bubblePosition the x position of the bubble if showing on top, the y position of the
+     *                       bubble if showing vertically.
+     * @return the position the tip of the pointer points to. The x position if showing on top, the
+     * y position if showing vertically.
+     */
+    public float getPointerPosition(float bubblePosition) {
+        // TODO: I don't understand why it works but it does - why normalized in portrait
+        //  & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation?
+        final float normalizedSize = IconNormalizer.getNormalizedCircleSize(
+                getBubbleSize());
+        return showBubblesVertically()
+                ? bubblePosition + (getBubbleSize() / 2f)
+                : bubblePosition + (normalizedSize / 2f) - mPointerWidth;
+    }
+
+    /**
+     * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
+     * row. When in landscape or on a large screen, they show at the left or right side in a
+     * vertical row. This method accounts for screen orientation and will return an x or y value
+     * for the position of the bubble in the row.
+     *
+     * @param index bubble index in the row.
+     * @param numberOfBubbles the number of bubbles (including the overflow) in the row.
+     * @return the y position of the bubble if showing vertically and the x position if showing
+     * horizontally.
+     */
+    public float getBubbleXOrYForOrientation(int index, int numberOfBubbles) {
+        final float positionInBar = index * (mBubbleSize + mSpacingBetweenBubbles);
+        final float expandedStackSize = (numberOfBubbles * mBubbleSize)
+                + ((numberOfBubbles - 1) * mSpacingBetweenBubbles);
+        final float centerPosition = showBubblesVertically()
+                ? mPositionRect.centerY()
+                : mPositionRect.centerX();
+        final float rowStart = centerPosition - (expandedStackSize / 2f);
+        return rowStart + positionInBar;
+    }
+
     /**
      * Sets the stack's most recent position along the edge of the screen. This is saved when the
      * last bubble is removed, so that the stack can be restored in its previous position.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 92e455c..2c6136b 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
@@ -874,8 +874,10 @@
                         mExpandedAnimationController.expandFromStack(() -> {
                             afterExpandedViewAnimation();
                         } /* after */);
+                        final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
+                                getBubbleIndex(mExpandedBubble));
                         mExpandedViewContainer.setTranslationX(0f);
-                        mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY());
+                        mExpandedViewContainer.setTranslationY(translationY);
                         mExpandedViewContainer.setAlpha(1f);
                     }
                     removeOnLayoutChangeListener(mOrientationChangedListener);
@@ -1524,6 +1526,7 @@
                     bubble.cleanupViews();
                 }
                 updatePointerPosition();
+                updateExpandedView();
                 logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
                 return;
             }
@@ -1815,9 +1818,10 @@
             mTaskbarScrim.setVisibility(VISIBLE);
             mTaskbarScrim.animate().alpha(1f).start();
         }
-
+        final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
+                getBubbleIndex(mExpandedBubble));
         mExpandedViewContainer.setTranslationX(0f);
-        mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY());
+        mExpandedViewContainer.setTranslationY(translationY);
         mExpandedViewContainer.setAlpha(1f);
 
         int index;
@@ -1866,7 +1870,7 @@
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     bubbleWillBeAt + mBubbleSize / 2f,
-                    mPositioner.getExpandedViewY());
+                    translationY);
         }
         mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
 
@@ -1970,7 +1974,7 @@
             mExpandedViewContainerMatrix.setScale(
                     1f, 1f,
                     expandingFromBubbleAt + mBubbleSize / 2f,
-                    mPositioner.getExpandedViewY());
+                    mPositioner.getExpandedViewY(mExpandedBubble, index));
         }
 
         mExpandedViewAlphaAnimator.reverse();
@@ -2077,7 +2081,7 @@
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                     expandingFromBubbleDestination + mBubbleSize / 2f,
-                    mPositioner.getExpandedViewY());
+                    mPositioner.getExpandedViewY(mExpandedBubble, expandingFromBubbleDestination));
         }
 
         mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -2698,7 +2702,9 @@
             mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
         }
         if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-            mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY());
+            mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY(mExpandedBubble,
+                    mExpandedAnimationController.getBubbleXOrYForOrientation(
+                            getBubbleIndex(mExpandedBubble))));
             mExpandedViewContainer.setTranslationX(0f);
             mExpandedBubble.getExpandedView().updateView(
                     mExpandedViewContainer.getLocationOnScreen());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index df2b440..efe07fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -83,12 +83,6 @@
     private float mBubblePaddingTop;
     /** Size of each bubble. */
     private float mBubbleSizePx;
-    /** Max number of bubbles shown in row above expanded view. */
-    private int mBubblesMaxRendered;
-    /** Max amount of space to have between bubbles when expanded. */
-    private int mBubblesMaxSpace;
-    /** Amount of space between the bubbles when expanded. */
-    private float mSpaceBetweenBubbles;
     /** Whether the expand / collapse animation is running. */
     private boolean mAnimatingExpand = false;
 
@@ -211,8 +205,6 @@
         mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
         mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
         mBubbleSizePx = mPositioner.getBubbleSize();
-        mBubblesMaxRendered = mPositioner.getMaxBubbles();
-        mSpaceBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
     }
 
     /**
@@ -628,14 +620,13 @@
         }
     }
 
-    // TODO - could move to method on bubblePositioner if mSpaceBetweenBubbles gets moved
     /**
      * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
      * row. When in landscape or on a large screen, they show at the left or right side in a
      * vertical row. This method accounts for screen orientation and will return an x or y value
      * for the position of the bubble in the row.
      *
-     * @param index Bubble index in row.
+     * @param index bubble index in the row.
      * @return the y position of the bubble if showing vertically and the x position if showing
      * horizontally.
      */
@@ -643,15 +634,6 @@
         if (mLayout == null) {
             return 0;
         }
-        final float positionInBar = index * (mBubbleSizePx + mSpaceBetweenBubbles);
-        Rect availableRect = mPositioner.getAvailableRect();
-        final boolean isLandscape = mPositioner.showBubblesVertically();
-        final float expandedStackSize = (mLayout.getChildCount() * mBubbleSizePx)
-                + ((mLayout.getChildCount() - 1) * mSpaceBetweenBubbles);
-        final float centerPosition = isLandscape
-                ? availableRect.centerY()
-                : availableRect.centerX();
-        final float rowStart = centerPosition - (expandedStackSize / 2f);
-        return rowStart + positionInBar;
+        return mPositioner.getBubbleXOrYForOrientation(index, mLayout.getChildCount());
     }
 }
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 e42f511..a79807b 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
@@ -92,12 +92,16 @@
     private DividerSnapAlgorithm mDividerSnapAlgorithm;
     private int mDividePosition;
     private boolean mInitialized = false;
+    private int mOrientation;
+    private int mRotation;
 
     public SplitLayout(String windowName, Context context, Configuration configuration,
             SplitLayoutHandler splitLayoutHandler,
             SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
             DisplayImeController displayImeController, ShellTaskOrganizer taskOrganizer) {
         mContext = context.createConfigurationContext(configuration);
+        mOrientation = configuration.orientation;
+        mRotation = configuration.windowConfiguration.getRotation();
         mSplitLayoutHandler = splitLayoutHandler;
         mDisplayImeController = displayImeController;
         mSplitWindowManager = new SplitWindowManager(
@@ -144,25 +148,36 @@
 
     /** Applies new configuration, returns {@code false} if there's no effect to the layout. */
     public boolean updateConfiguration(Configuration configuration) {
+        boolean affectsLayout = false;
+
+        // Make sure to render the divider bar with proper resources that matching the screen
+        // orientation.
+        final int orientation = configuration.orientation;
+        if (orientation != mOrientation) {
+            mOrientation = orientation;
+            mContext = mContext.createConfigurationContext(configuration);
+            mSplitWindowManager.setConfiguration(configuration);
+            affectsLayout = true;
+        }
+
+        // Update the split bounds when necessary. Besides root bounds changed, split bounds need to
+        // be updated when the rotation changed to cover the case that users rotated the screen 180
+        // degrees.
+        final int rotation = configuration.windowConfiguration.getRotation();
         final Rect rootBounds = configuration.windowConfiguration.getBounds();
-        if (mRootBounds.equals(rootBounds)) {
-            return false;
+        if (rotation != mRotation || !mRootBounds.equals(rootBounds)) {
+            mRootBounds.set(rootBounds);
+            mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
+            resetDividerPosition();
+            affectsLayout = true;
         }
 
-        mContext = mContext.createConfigurationContext(configuration);
-        mSplitWindowManager.setConfiguration(configuration);
-        mRootBounds.set(rootBounds);
-        mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
-        resetDividerPosition();
-
-        // Don't inflate divider bar if it is not initialized.
-        if (!mInitialized) {
-            return false;
+        if (mInitialized) {
+            release();
+            init();
         }
 
-        release();
-        init();
-        return true;
+        return affectsLayout;
     }
 
     /** Updates recording bounds of divider window and both of the splits. */
@@ -296,9 +311,8 @@
         return context.getSystemService(WindowManager.class)
                 .getMaximumWindowMetrics()
                 .getWindowInsets()
-                .getInsets(WindowInsets.Type.navigationBars()
-                        | WindowInsets.Type.statusBars()
-                        | WindowInsets.Type.displayCutout()).toRect();
+                .getInsets(WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout())
+                .toRect();
     }
 
     private static boolean isLandscape(Rect bounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
index d9409ec..b1fa2ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java
@@ -204,7 +204,8 @@
 
     @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         if (transition != mPendingDismiss && transition != mPendingEnter) {
             // If we're not in split-mode, just abort
@@ -239,12 +240,12 @@
                 if (change.getParent() != null) {
                     // This is probably reparented, so we want the parent to be immediately visible
                     final TransitionInfo.Change parentChange = info.getChange(change.getParent());
-                    t.show(parentChange.getLeash());
-                    t.setAlpha(parentChange.getLeash(), 1.f);
+                    startTransaction.show(parentChange.getLeash());
+                    startTransaction.setAlpha(parentChange.getLeash(), 1.f);
                     // and then animate this layer outside the parent (since, for example, this is
                     // the home task animating from fullscreen to part-screen).
-                    t.reparent(leash, info.getRootLeash());
-                    t.setLayer(leash, info.getChanges().size() - i);
+                    startTransaction.reparent(leash, info.getRootLeash());
+                    startTransaction.setLayer(leash, info.getChanges().size() - i);
                     // build the finish reparent/reposition
                     mFinishTransaction.reparent(leash, parentChange.getLeash());
                     mFinishTransaction.setPosition(leash,
@@ -271,12 +272,12 @@
             if (transition == mPendingEnter
                     && mListener.mPrimary.token.equals(change.getContainer())
                     || mListener.mSecondary.token.equals(change.getContainer())) {
-                t.setWindowCrop(leash, change.getStartAbsBounds().width(),
+                startTransaction.setWindowCrop(leash, change.getStartAbsBounds().width(),
                         change.getStartAbsBounds().height());
                 if (mListener.mPrimary.token.equals(change.getContainer())) {
                     // Move layer to top since we want it above the oversized home task during
                     // animation even though home task is on top in hierarchy.
-                    t.setLayer(leash, info.getChanges().size() + 1);
+                    startTransaction.setLayer(leash, info.getChanges().size() + 1);
                 }
             }
             boolean isOpening = Transitions.isOpeningType(info.getType());
@@ -289,7 +290,7 @@
                     // Dismissing via snap-to-top/bottom means that the dismissed task is already
                     // not-visible (usually cropped to oblivion) so immediately set its alpha to 0
                     // and don't animate it so it doesn't pop-in when reparented.
-                    t.setAlpha(leash, 0.f);
+                    startTransaction.setAlpha(leash, 0.f);
                 } else {
                     startExampleAnimation(leash, false /* show */);
                 }
@@ -311,7 +312,7 @@
             }
             mSplitScreen.finishEnterSplitTransition(homeIsVisible);
         }
-        t.apply();
+        startTransaction.apply();
         onFinish();
         return true;
     }
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 324a6e2..fbd6064 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
@@ -107,38 +107,6 @@
      */
     private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000;
 
-    // Not a complete set of states but serves what we want right now.
-    private enum State {
-        UNDEFINED(0),
-        TASK_APPEARED(1),
-        ENTRY_SCHEDULED(2),
-        ENTERING_PIP(3),
-        ENTERED_PIP(4),
-        EXITING_PIP(5);
-
-        private final int mStateValue;
-
-        State(int value) {
-            mStateValue = value;
-        }
-
-        private boolean isInPip() {
-            return mStateValue >= TASK_APPEARED.mStateValue
-                    && mStateValue != EXITING_PIP.mStateValue;
-        }
-
-        /**
-         * Resize request can be initiated in other component, ignore if we are no longer in PIP,
-         * still waiting for animation or we're exiting from it.
-         *
-         * @return {@code true} if the resize request should be blocked/ignored.
-         */
-        private boolean shouldBlockResizeRequest() {
-            return mStateValue < ENTERING_PIP.mStateValue
-                    || mStateValue == EXITING_PIP.mStateValue;
-        }
-    }
-
     private final Context mContext;
     private final SyncTransactionQueue mSyncTransactionQueue;
     private final PipBoundsState mPipBoundsState;
@@ -190,7 +158,8 @@
             }
             final boolean isExitPipDirection = isOutPipDirection(direction)
                     || isRemovePipDirection(direction);
-            if (mState != State.EXITING_PIP || isExitPipDirection) {
+            if (mPipTransitionState.getTransitionState() != PipTransitionState.EXITING_PIP
+                    || isExitPipDirection) {
                 // Finish resize as long as we're not exiting PIP, or, if we are, only if this is
                 // the end of an exit PIP animation.
                 // This is necessary in case there was a resize animation ongoing when exit PIP
@@ -233,7 +202,7 @@
     private ActivityManager.RunningTaskInfo mDeferredTaskInfo;
     private WindowContainerToken mToken;
     private SurfaceControl mLeash;
-    private State mState = State.UNDEFINED;
+    private PipTransitionState mPipTransitionState;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
     private long mLastOneShotAlphaAnimationTime;
     private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
@@ -278,6 +247,7 @@
 
     public PipTaskOrganizer(Context context,
             @NonNull SyncTransactionQueue syncTransactionQueue,
+            @NonNull PipTransitionState pipTransitionState,
             @NonNull PipBoundsState pipBoundsState,
             @NonNull PipBoundsAlgorithm boundsHandler,
             @NonNull PipMenuController pipMenuController,
@@ -291,6 +261,7 @@
             @ShellMainThread ShellExecutor mainExecutor) {
         mContext = context;
         mSyncTransactionQueue = syncTransactionQueue;
+        mPipTransitionState = pipTransitionState;
         mPipBoundsState = pipBoundsState;
         mPipBoundsAlgorithm = boundsHandler;
         mPipMenuController = pipMenuController;
@@ -326,14 +297,14 @@
     }
 
     public boolean isInPip() {
-        return mState.isInPip();
+        return mPipTransitionState.isInPip();
     }
 
     /**
      * Returns whether the entry animation is waiting to be started.
      */
     public boolean isEntryScheduled() {
-        return mState == State.ENTRY_SCHEDULED;
+        return mPipTransitionState.getTransitionState() == PipTransitionState.ENTRY_SCHEDULED;
     }
 
     /**
@@ -401,9 +372,11 @@
      * @param animationDurationMs duration in millisecond for the exiting PiP transition
      */
     public void exitPip(int animationDurationMs) {
-        if (!mState.isInPip() || mState == State.EXITING_PIP || mToken == null) {
+        if (!mPipTransitionState.isInPip()
+                || mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
+                || mToken == null) {
             Log.wtf(TAG, "Not allowed to exitPip in current state"
-                    + " mState=" + mState + " mToken=" + mToken);
+                    + " mState=" + mPipTransitionState.getTransitionState() + " mToken=" + mToken);
             return;
         }
 
@@ -427,7 +400,12 @@
         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.
-        mState = State.EXITING_PIP;
+        mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
+
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+            mPipTransitionController.startTransition(destinationBounds, wct);
+            return;
+        }
         mSyncTransactionQueue.queue(wct);
         mSyncTransactionQueue.runInSync(t -> {
             // Make sure to grab the latest source hint rect as it could have been
@@ -465,9 +443,9 @@
      * Removes PiP immediately.
      */
     public void removePip() {
-        if (!mState.isInPip() ||  mToken == null) {
+        if (!mPipTransitionState.isInPip() ||  mToken == null) {
             Log.wtf(TAG, "Not allowed to removePip in current state"
-                    + " mState=" + mState + " mToken=" + mToken);
+                    + " mState=" + mPipTransitionState.getTransitionState() + " mToken=" + mToken);
             return;
         }
 
@@ -481,10 +459,19 @@
         animator.setDuration(mExitAnimationDuration);
         animator.setInterpolator(Interpolators.ALPHA_OUT);
         animator.start();
-        mState = State.EXITING_PIP;
+        mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
     }
 
     private void removePipImmediately() {
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+            final WindowContainerTransaction wct = new WindowContainerTransaction();
+            wct.setBounds(mToken, null);
+            wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+            wct.reorder(mToken, false);
+            mPipTransitionController.startTransition(null, wct);
+            return;
+        }
+
         try {
             // Reset the task bounds first to ensure the activity configuration is reset as well
             final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -503,7 +490,7 @@
         Objects.requireNonNull(info, "Requires RunningTaskInfo");
         mTaskInfo = info;
         mToken = mTaskInfo.token;
-        mState = State.TASK_APPEARED;
+        mPipTransitionState.setTransitionState(PipTransitionState.TASK_APPEARED);
         mLeash = leash;
         mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
         setBoundsStateForEntry(mTaskInfo.topActivity, mPictureInPictureParams,
@@ -546,6 +533,8 @@
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
                 mPipMenuController.attach(mLeash);
+            } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+                mOneShotAnimationType = ANIM_TYPE_BOUNDS;
             }
             return;
         }
@@ -557,7 +546,7 @@
             scheduleAnimateResizePip(currentBounds, destinationBounds, 0 /* startingAngle */,
                     sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration,
                     null /* updateBoundsCallback */);
-            mState = State.ENTERING_PIP;
+            mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
             enterPipWithAlphaAnimation(destinationBounds, mEnterAnimationDuration);
             mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -584,7 +573,7 @@
         final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
         animateResizePip(currentBounds, destinationBounds, sourceHintRect,
                 TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration, 0 /* startingAngle */);
-        mState = State.ENTERING_PIP;
+        mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
     }
 
     /**
@@ -609,7 +598,7 @@
                 mSurfaceControlTransactionFactory.getTransaction();
         tx.setAlpha(mLeash, 0f);
         tx.apply();
-        mState = State.ENTRY_SCHEDULED;
+        mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED);
         applyEnterPipSyncTransaction(destinationBounds, () -> {
             mPipAnimationController
                     .getAnimator(mTaskInfo, mLeash, destinationBounds, 0f, 1f)
@@ -620,7 +609,7 @@
                     .start();
             // mState is set right after the animation is kicked off to block any resize
             // requests such as offsetPip that may have been called prior to the transition.
-            mState = State.ENTERING_PIP;
+            mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
         }, null /* boundsChangeTransaction */);
     }
 
@@ -667,7 +656,7 @@
     private void sendOnPipTransitionStarted(
             @PipAnimationController.TransitionDirection int direction) {
         if (direction == TRANSITION_DIRECTION_TO_PIP) {
-            mState = State.ENTERING_PIP;
+            mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
         }
         mPipTransitionController.sendOnPipTransitionStarted(direction);
     }
@@ -676,7 +665,7 @@
     void sendOnPipTransitionFinished(
             @PipAnimationController.TransitionDirection int direction) {
         if (direction == TRANSITION_DIRECTION_TO_PIP) {
-            mState = State.ENTERED_PIP;
+            mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP);
         }
         mPipTransitionController.sendOnPipTransitionFinished(direction);
         // Apply the deferred RunningTaskInfo if applicable after all proper callbacks are sent.
@@ -701,7 +690,7 @@
      */
     @Override
     public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
-        if (mState == State.UNDEFINED) {
+        if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
             return;
         }
         final WindowContainerToken token = info.token;
@@ -713,7 +702,7 @@
         clearWaitForFixedRotation();
         mInSwipePipToHomeTransition = false;
         mPictureInPictureParams = null;
-        mState = State.UNDEFINED;
+        mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
         // Re-set the PIP bounds to none.
         mPipBoundsState.setBounds(new Rect());
         mPipUiEventLoggerLogger.setTaskInfo(null);
@@ -727,8 +716,10 @@
     @Override
     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
         Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
-        if (mState != State.ENTERED_PIP && mState != State.EXITING_PIP) {
-            Log.d(TAG, "Defer onTaskInfoChange in current state: " + mState);
+        if (mPipTransitionState.getTransitionState() != PipTransitionState.ENTERED_PIP
+                && mPipTransitionState.getTransitionState() != PipTransitionState.EXITING_PIP) {
+            Log.d(TAG, "Defer onTaskInfoChange in current state: "
+                    + mPipTransitionState.getTransitionState());
             // Defer applying PiP parameters if the task is entering PiP to avoid disturbing
             // the animation.
             mDeferredTaskInfo = info;
@@ -761,7 +752,7 @@
         mNextRotation = newRotation;
         mWaitForFixedRotation = true;
 
-        if (mState.isInPip()) {
+        if (mPipTransitionState.isInPip()) {
             // Fade out the existing PiP to avoid jump cut during seamless rotation.
             fadeExistingPip(false /* show */);
         }
@@ -772,7 +763,7 @@
         if (!mWaitForFixedRotation) {
             return;
         }
-        if (mState == State.TASK_APPEARED) {
+        if (mPipTransitionState.getTransitionState() == PipTransitionState.TASK_APPEARED) {
             if (mInSwipePipToHomeTransition) {
                 onEndOfSwipePipToHomeTransition();
             } else {
@@ -780,9 +771,11 @@
                 enterPipWithAlphaAnimation(mPipBoundsAlgorithm.getEntryDestinationBounds(),
                         mEnterAnimationDuration);
             }
-        } else if (mState == State.ENTERED_PIP && mHasFadeOut) {
+        } else if (mPipTransitionState.getTransitionState() == PipTransitionState.ENTERED_PIP
+                && mHasFadeOut) {
             fadeExistingPip(true /* show */);
-        } else if (mState == State.ENTERING_PIP && mDeferredAnimEndTransaction != null) {
+        } else if (mPipTransitionState.getTransitionState() == PipTransitionState.ENTERING_PIP
+                && mDeferredAnimEndTransaction != null) {
             final PipAnimationController.PipTransitionAnimator<?> animator =
                     mPipAnimationController.getCurrentAnimator();
             final Rect destinationBounds = animator.getDestinationBounds();
@@ -836,13 +829,13 @@
         // note that this can be called when swipe-to-home or fixed-rotation is happening.
         // Skip this entirely if that's the case.
         final boolean waitForFixedRotationOnEnteringPip = mWaitForFixedRotation
-                && (mState != State.ENTERED_PIP);
+                && (mPipTransitionState.getTransitionState() != PipTransitionState.ENTERED_PIP);
         if ((mInSwipePipToHomeTransition || waitForFixedRotationOnEnteringPip) && fromRotation) {
             if (DEBUG) {
                 Log.d(TAG, "Skip onMovementBoundsChanged on rotation change"
                         + " mInSwipePipToHomeTransition=" + mInSwipePipToHomeTransition
                         + " mWaitForFixedRotation=" + mWaitForFixedRotation
-                        + " mState=" + mState);
+                        + " getTransitionState=" + mPipTransitionState.getTransitionState());
             }
             return;
         }
@@ -850,7 +843,7 @@
                 mPipAnimationController.getCurrentAnimator();
         if (animator == null || !animator.isRunning()
                 || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
-            final boolean rotatingPip = mState.isInPip() && fromRotation;
+            final boolean rotatingPip = mPipTransitionState.isInPip() && fromRotation;
             if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) {
                 // The position will be used by fade-in animation when the fixed rotation is done.
                 mPipBoundsState.setBounds(destinationBoundsOut);
@@ -983,7 +976,7 @@
             Rect currentBounds, Rect destinationBounds, float startingAngle, Rect sourceHintRect,
             @PipAnimationController.TransitionDirection int direction, int durationMs,
             Consumer<Rect> updateBoundsCallback) {
-        if (!mState.isInPip()) {
+        if (!mPipTransitionState.isInPip()) {
             // TODO: tend to use shouldBlockResizeRequest here as well but need to consider
             // the fact that when in exitPip, scheduleAnimateResizePip is executed in the window
             // container transaction callback and we want to set the mState immediately.
@@ -1013,7 +1006,7 @@
         final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
         mSurfaceTransactionHelper
                 .crop(tx, mLeash, toBounds)
-                .round(tx, mLeash, mState.isInPip());
+                .round(tx, mLeash, mPipTransitionState.isInPip());
         if (mPipMenuController.isMenuVisible()) {
             mPipMenuController.resizePipMenu(mLeash, tx, toBounds);
         } else {
@@ -1091,7 +1084,7 @@
     public void scheduleFinishResizePip(Rect destinationBounds,
             @PipAnimationController.TransitionDirection int direction,
             Consumer<Rect> updateBoundsCallback) {
-        if (mState.shouldBlockResizeRequest()) {
+        if (mPipTransitionState.shouldBlockResizeRequest()) {
             return;
         }
 
@@ -1108,7 +1101,7 @@
         mSurfaceTransactionHelper
                 .crop(tx, mLeash, destinationBounds)
                 .resetScale(tx, mLeash, destinationBounds)
-                .round(tx, mLeash, mState.isInPip());
+                .round(tx, mLeash, mPipTransitionState.isInPip());
         return tx;
     }
 
@@ -1117,7 +1110,7 @@
      */
     public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
             Consumer<Rect> updateBoundsCallback) {
-        if (mState.shouldBlockResizeRequest()) {
+        if (mPipTransitionState.shouldBlockResizeRequest()) {
             return;
         }
         if (mWaitForFixedRotation) {
@@ -1375,7 +1368,7 @@
         pw.println(innerPrefix + "mToken=" + mToken
                 + " binder=" + (mToken != null ? mToken.asBinder() : null));
         pw.println(innerPrefix + "mLeash=" + mLeash);
-        pw.println(innerPrefix + "mState=" + mState);
+        pw.println(innerPrefix + "mState=" + mPipTransitionState.getTransitionState());
         pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
         pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
     }
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 4759550..b75cde0 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
@@ -18,6 +18,8 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.WindowManager.TRANSIT_PIP;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
@@ -25,6 +27,8 @@
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
 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_REMOVE_PIP;
 
 import android.app.TaskInfo;
 import android.content.Context;
@@ -35,6 +39,7 @@
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -49,64 +54,166 @@
  */
 public class PipTransition extends PipTransitionController {
 
+    private final PipTransitionState mPipTransitionState;
     private final int mEnterExitAnimationDuration;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
     private Transitions.TransitionFinishCallback mFinishCallback;
+    private Rect mExitDestinationBounds = new Rect();
 
     public PipTransition(Context context,
-            PipBoundsState pipBoundsState, PipMenuController pipMenuController,
+            PipBoundsState pipBoundsState,
+            PipTransitionState pipTransitionState,
+            PipMenuController pipMenuController,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipAnimationController pipAnimationController,
             Transitions transitions,
             @NonNull ShellTaskOrganizer shellTaskOrganizer) {
         super(pipBoundsState, pipMenuController, pipBoundsAlgorithm,
                 pipAnimationController, transitions, shellTaskOrganizer);
+        mPipTransitionState = pipTransitionState;
         mEnterExitAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipResizeAnimationDuration);
     }
 
     @Override
+    public void setIsFullAnimation(boolean isFullAnimation) {
+        setOneShotAnimationType(isFullAnimation ? ANIM_TYPE_BOUNDS : ANIM_TYPE_ALPHA);
+    }
+
+    /**
+     * Sets the preferred animation type for one time.
+     * This is typically used to set the animation type to
+     * {@link PipAnimationController#ANIM_TYPE_ALPHA}.
+     */
+    private void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) {
+        mOneShotAnimationType = animationType;
+    }
+
+    @Override
+    public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
+        if (destinationBounds != null) {
+            mExitDestinationBounds.set(destinationBounds);
+            mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
+        } else {
+            mTransitions.startTransition(TRANSIT_REMOVE_PIP, out, this);
+        }
+    }
+
+    @Override
     public boolean startAnimation(@android.annotation.NonNull IBinder transition,
             @android.annotation.NonNull TransitionInfo info,
-            @android.annotation.NonNull SurfaceControl.Transaction t,
+            @android.annotation.NonNull SurfaceControl.Transaction startTransaction,
+            @android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
             @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) {
+
+        if (info.getType() == TRANSIT_EXIT_PIP && info.getChanges().size() == 1) {
+            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;
+        }
+
+        if (info.getType() == TRANSIT_REMOVE_PIP) {
+            startTransaction.apply();
+            finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
+                    mPipBoundsState.getDisplayBounds());
+            finishCallback.onTransitionFinished(null, null);
+            return true;
+        }
+
+        // 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) {
-                mFinishCallback = finishCallback;
-                return startEnterAnimation(change.getTaskInfo(), change.getLeash(), t);
+                enterPip = change;
+            } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+                wallpaper = change;
             }
         }
-        return false;
+        if (enterPip == null) {
+            return false;
+        }
+
+        // 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);
     }
 
     @Nullable
     @Override
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
             @NonNull TransitionRequestInfo request) {
-        return null;
+        if (request.getType() == TRANSIT_PIP) {
+            WindowContainerTransaction wct = new WindowContainerTransaction();
+            mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED);
+            final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
+            wct.setActivityWindowingMode(request.getTriggerTask().token, WINDOWING_MODE_UNDEFINED);
+            wct.setBounds(request.getTriggerTask().token, destinationBounds);
+            return wct;
+        } else {
+            return null;
+        }
     }
 
     @Override
     public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
             @PipAnimationController.TransitionDirection int direction,
             SurfaceControl.Transaction tx) {
+
+        if (isInPipDirection(direction)) {
+            mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP);
+        }
         WindowContainerTransaction wct = new WindowContainerTransaction();
         prepareFinishResizeTransaction(taskInfo, destinationBounds,
                 direction, tx, wct);
-        mFinishCallback.onTransitionFinished(wct, null);
+        mFinishCallback.onTransitionFinished(wct, new WindowContainerTransactionCallback() {
+            @Override
+            public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) {
+                t.merge(tx);
+                t.apply();
+            }
+        });
         finishResizeForMenu(destinationBounds);
     }
 
+    private boolean startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
+            final Rect destinationBounds) {
+        PipAnimationController.PipTransitionAnimator animator =
+                mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
+                        mPipBoundsState.getBounds(), destinationBounds, null,
+                        TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, Surface.ROTATION_0);
+
+        animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
+                .setPipAnimationCallback(mPipAnimationCallback)
+                .setDuration(mEnterExitAnimationDuration)
+                .start();
+
+        return true;
+    }
+
     private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
-            final SurfaceControl.Transaction t) {
+            final SurfaceControl.Transaction startTransaction,
+            final SurfaceControl.Transaction finishTransaction) {
         setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
                 taskInfo.topActivityInfo);
         final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
         final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
         PipAnimationController.PipTransitionAnimator animator;
+        finishTransaction.setPosition(leash, destinationBounds.left, destinationBounds.top);
         if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
             final Rect sourceHintRect =
                     PipBoundsAlgorithm.getValidSourceHintRect(
@@ -115,8 +222,10 @@
                     currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
                     0 /* startingAngle */, Surface.ROTATION_0);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
-            t.setAlpha(leash, 0f);
-            t.apply();
+            startTransaction.setAlpha(leash, 0f);
+            // PiP menu is attached late in the process here to avoid any artifacts on the leash
+            // caused by addShellRoot when in gesture navigation mode.
+            mPipMenuController.attach(leash);
             animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
                     0f, 1f);
             mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -124,6 +233,7 @@
             throw new RuntimeException("Unrecognized animation type: "
                     + mOneShotAnimationType);
         }
+        startTransaction.apply();
         animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
                 .setPipAnimationCallback(mPipAnimationCallback)
                 .setDuration(mEnterExitAnimationDuration)
@@ -158,6 +268,5 @@
         }
 
         wct.setBounds(taskInfo.token, taskBounds);
-        wct.setBoundsChangeTransaction(taskInfo.token, tx);
     }
 }
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 d801c91..dedc566 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
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
 
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.transition.Transitions;
@@ -46,6 +47,7 @@
     protected final PipBoundsState mPipBoundsState;
     protected final ShellTaskOrganizer mShellTaskOrganizer;
     protected final PipMenuController mPipMenuController;
+    protected final Transitions mTransitions;
     private final Handler mMainHandler;
     private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
 
@@ -98,6 +100,22 @@
             SurfaceControl.Transaction tx) {
     }
 
+    /**
+     * Called to inform the transition that the animation should start with the assumption that
+     * PiP is not animating from its original bounds, but rather a continuation of another
+     * animation. For example, gesture navigation would first fade out the PiP activity, and the
+     * transition should be responsible to animate in (such as fade in) the PiP.
+     */
+    public void setIsFullAnimation(boolean isFullAnimation) {
+    }
+
+    /**
+     * Called when the Shell wants to starts a transition/animation.
+     */
+    public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
+        // Default implementation does nothing.
+    }
+
     public PipTransitionController(PipBoundsState pipBoundsState,
             PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
             PipAnimationController pipAnimationController, Transitions transitions,
@@ -107,6 +125,7 @@
         mShellTaskOrganizer = shellTaskOrganizer;
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipAnimationController = pipAnimationController;
+        mTransitions = transitions;
         mMainHandler = new Handler(Looper.getMainLooper());
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             transitions.addHandler(this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
new file mode 100644
index 0000000..d23aada
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used to keep track of PiP leash state as it appears and animates by {@link PipTaskOrganizer} and
+ * {@link PipTransition}.
+ */
+public class PipTransitionState {
+
+    public static final int UNDEFINED = 0;
+    public static final int TASK_APPEARED = 1;
+    public static final int ENTRY_SCHEDULED = 2;
+    public static final int ENTERING_PIP = 3;
+    public static final int ENTERED_PIP = 4;
+    public static final int EXITING_PIP = 5;
+
+    // Not a complete set of states but serves what we want right now.
+    @IntDef(prefix = { "TRANSITION_STATE_" }, value =  {
+            UNDEFINED,
+            TASK_APPEARED,
+            ENTRY_SCHEDULED,
+            ENTERING_PIP,
+            ENTERED_PIP,
+            EXITING_PIP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TransitionState {}
+
+    private @TransitionState int mState;
+
+    public PipTransitionState() {
+        mState = UNDEFINED;
+    }
+
+    public void setTransitionState(@TransitionState int state) {
+        mState = state;
+    }
+
+    public @TransitionState int getTransitionState() {
+        return mState;
+    }
+
+    public boolean isInPip() {
+        return mState >= TASK_APPEARED
+                && mState != EXITING_PIP;
+    }
+
+    /**
+     * Resize request can be initiated in other component, ignore if we are no longer in PIP,
+     * still waiting for animation or we're exiting from it.
+     *
+     * @return {@code true} if the resize request should be blocked/ignored.
+     */
+    public boolean shouldBlockResizeRequest() {
+        return mState < ENTERING_PIP
+                || mState == EXITING_PIP;
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 4f3ec96..62b50c5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -67,6 +67,7 @@
 import com.android.wm.shell.pip.IPipAnimationListener;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipMediaController;
@@ -528,6 +529,8 @@
 
     private void setPinnedStackAnimationType(int animationType) {
         mPipTaskOrganizer.setOneShotAnimationType(animationType);
+        mPipTransitionController.setIsFullAnimation(
+                animationType == PipAnimationController.ANIM_TYPE_BOUNDS);
     }
 
     private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
index b7caf72..551476d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
@@ -58,7 +58,8 @@
 
     @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         return false;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
new file mode 100644
index 0000000..5d5a6e5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.view.IWindow;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+import android.view.WindowlessWindowManager;
+
+import com.android.wm.shell.R;
+
+import java.util.function.Supplier;
+
+/**
+ * Handles drawing outline of the bounds of provided root surface. The outline will be drown with
+ * the consideration of display insets like status bar, navigation bar and display cutout.
+ */
+class OutlineManager extends WindowlessWindowManager {
+    private static final String WINDOW_NAME = "SplitOutlineLayer";
+    private final Context mContext;
+    private final int mOutlineColor;
+    private final Rect mOutlineBounds = new Rect();
+    private final Rect mTmpBounds = new Rect();
+    private final Supplier<SurfaceControl> mOutlineSurfaceSupplier;
+    private SurfaceControlViewHost mViewHost;
+
+    /**
+     * Constructs {@link #OutlineManager} with indicated outline color for the provided root
+     * surface.
+     */
+    OutlineManager(Context context, Configuration configuration,
+            Supplier<SurfaceControl> outlineSurfaceSupplier, int color) {
+        super(configuration, null /* rootSurface */, null /* hostInputToken */);
+        mContext = context.createDisplayContext(context.getDisplay());
+        mOutlineSurfaceSupplier = outlineSurfaceSupplier;
+        mOutlineColor = color;
+    }
+
+    @Override
+    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+        b.setParent(mOutlineSurfaceSupplier.get());
+    }
+
+    boolean updateOutlineBounds(Rect rootBounds) {
+        computeOutlineBounds(mContext, rootBounds, mTmpBounds);
+        if (mOutlineBounds.equals(mTmpBounds)) {
+            return false;
+        }
+        mOutlineBounds.set(mTmpBounds);
+
+        if (mViewHost == null) {
+            mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+        }
+        if (mViewHost.getView() == null) {
+            final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext)
+                    .inflate(R.layout.split_outline, null);
+            rootView.updateOutlineBounds(mOutlineBounds, mOutlineColor);
+
+            final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                    rootBounds.width(), rootBounds.height(),
+                    TYPE_APPLICATION_OVERLAY,
+                    FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE,
+                    PixelFormat.TRANSLUCENT);
+            lp.token = new Binder();
+            lp.setTitle(WINDOW_NAME);
+            lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+            // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
+            //  TRUSTED_OVERLAY for windowless window without input channel.
+            mViewHost.setView(rootView, lp);
+        } else {
+            ((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor);
+            final WindowManager.LayoutParams lp =
+                    (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
+            lp.width = rootBounds.width();
+            lp.height = rootBounds.height();
+            mViewHost.relayout(lp);
+        }
+
+        return true;
+    }
+
+    private static void computeOutlineBounds(Context context, Rect rootBounds, Rect outBounds) {
+        computeDisplayStableBounds(context, outBounds);
+        outBounds.intersect(rootBounds);
+        // Offset the coordinate from screen based to surface based.
+        outBounds.offset(-rootBounds.left, -rootBounds.top);
+    }
+
+    private static void computeDisplayStableBounds(Context context, Rect outBounds) {
+        final WindowMetrics windowMetrics =
+                context.getSystemService(WindowManager.class).getMaximumWindowMetrics();
+        outBounds.set(windowMetrics.getBounds());
+        outBounds.inset(windowMetrics.getWindowInsets().getInsets(
+                WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()));
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineRoot.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineRoot.java
new file mode 100644
index 0000000..71d48ee
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineRoot.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+
+/** Root layout for holding split outline. */
+public class OutlineRoot extends FrameLayout {
+    public OutlineRoot(@NonNull Context context) {
+        super(context);
+    }
+
+    public OutlineRoot(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public OutlineRoot(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public OutlineRoot(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    private OutlineView mOutlineView;
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mOutlineView = findViewById(R.id.split_outline);
+    }
+
+    void updateOutlineBounds(Rect bounds, int color) {
+        mOutlineView.updateOutlineBounds(bounds, color);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java
new file mode 100644
index 0000000..ea66180
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.R;
+
+/** View for drawing split outline. */
+public class OutlineView extends View {
+    private final Paint mPaint = new Paint();
+    private final Rect mBounds = new Rect();
+
+    public OutlineView(@NonNull Context context) {
+        super(context);
+    }
+
+    public OutlineView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setStrokeWidth(getResources()
+                .getDimension(R.dimen.accessibility_focus_highlight_stroke_width));
+    }
+
+    void updateOutlineBounds(Rect bounds, int color) {
+        if (mBounds.equals(bounds) && mPaint.getColor() == color) return;
+        mBounds.set(bounds);
+        mPaint.setColor(color);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mBounds.isEmpty()) return;
+        final Path path = new Region(mBounds).getBoundaryPath();
+        canvas.drawPath(path, mPaint);
+    }
+}
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 82f95a4..a0bdcc3 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
@@ -16,8 +16,12 @@
 
 package com.android.wm.shell.splitscreen;
 
+import android.annotation.CallSuper;
 import android.app.ActivityManager;
+import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
@@ -28,15 +32,19 @@
 /**
  * Side stage for split-screen mode. Only tasks that are explicitly pinned to this stage show up
  * here. All other task are launch in the {@link MainStage}.
+ *
  * @see StageCoordinator
  */
 class SideStage extends StageTaskListener {
     private static final String TAG = SideStage.class.getSimpleName();
+    private final Context mContext;
+    private OutlineManager mOutlineManager;
 
-    SideStage(ShellTaskOrganizer taskOrganizer, int displayId,
+    SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
             StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
             SurfaceSession surfaceSession) {
         super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession);
+        mContext = context;
     }
 
     void addTask(ActivityManager.RunningTaskInfo task, Rect rootBounds,
@@ -69,4 +77,26 @@
         wct.reparent(task.token, newParent, false /* onTop */);
         return true;
     }
+
+    @Override
+    @CallSuper
+    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+        super.onTaskAppeared(taskInfo, leash);
+        if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) {
+            mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration,
+                    () -> mRootLeash,
+                    Color.YELLOW);
+        }
+    }
+
+    @Override
+    @CallSuper
+    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+        super.onTaskInfoChanged(taskInfo);
+        if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId
+                && mRootTaskInfo.isRunning) {
+            mOutlineManager.updateOutlineBounds(
+                    mRootTaskInfo.configuration.windowConfiguration.getBounds());
+        }
+    }
 }
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 002bfb6..d6afeba 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
@@ -64,6 +64,12 @@
         return null;
     }
 
+    /**
+     * Called when the keyguard occluded state changes.
+     * @param occluded Indicates if the keyguard is now occluded.
+     */
+    void onKeyguardOccludedChanged(boolean occluded);
+
     /** 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 9a457b5..89e6ca8 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
@@ -157,6 +157,10 @@
         mStageCoordinator.exitSplitScreen();
     }
 
+    public void onKeyguardOccludedChanged(boolean occluded) {
+        mStageCoordinator.onKeyguardOccludedChanged(occluded);
+    }
+
     public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
     }
@@ -284,6 +288,13 @@
             mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
             return mISplitScreen;
         }
+
+        @Override
+        public void onKeyguardOccludedChanged(boolean occluded) {
+            mMainExecutor.execute(() -> {
+                SplitScreenController.this.onKeyguardOccludedChanged(occluded);
+            });
+        }
     }
 
     /**
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 c37789e..69d0be6 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
@@ -84,17 +84,19 @@
     }
 
     void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback,
             @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot) {
         mFinishCallback = finishCallback;
         mAnimatingTransition = transition;
         if (mRemoteHandler != null) {
-            mRemoteHandler.startAnimation(transition, info, t, mRemoteFinishCB);
+            mRemoteHandler.startAnimation(transition, info, startTransaction, finishTransaction,
+                    mRemoteFinishCB);
             mRemoteHandler = null;
             return;
         }
-        playInternalAnimation(transition, info, t, mainRoot, sideRoot);
+        playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot);
     }
 
     private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
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 0264c5a..c6aacb1 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
@@ -44,6 +44,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.graphics.Rect;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.util.Log;
@@ -115,7 +116,8 @@
     private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
     private final DisplayImeController mDisplayImeController;
     private final SplitScreenTransitions mSplitTransitions;
-    private boolean mExitSplitScreenOnHide = true;
+    private boolean mExitSplitScreenOnHide;
+    private boolean mKeyguardOccluded;
 
     // TODO(b/187041611): remove this flag after totally deprecated legacy split
     /** Whether the device is supporting legacy split or not. */
@@ -150,6 +152,7 @@
                 mSyncQueue,
                 mSurfaceSession);
         mSideStage = new SideStage(
+                mContext,
                 mTaskOrganizer,
                 mDisplayId,
                 mSideStageListener,
@@ -157,6 +160,10 @@
                 mSurfaceSession);
         mDisplayImeController = displayImeController;
         mRootTDAOrganizer.registerListener(displayId, this);
+        final DeviceStateManager deviceStateManager =
+                mContext.getSystemService(DeviceStateManager.class);
+        deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
+                new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged));
         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                 mOnTransitionAnimationComplete);
         transitions.addHandler(this);
@@ -253,17 +260,17 @@
     }
 
     void setSideStagePosition(@SplitPosition int sideStagePosition) {
-        setSideStagePosition(sideStagePosition, true /* updateVisibility */);
+        setSideStagePosition(sideStagePosition, true /* updateBounds */);
     }
 
     private void setSideStagePosition(@SplitPosition int sideStagePosition,
-            boolean updateVisibility) {
+            boolean updateBounds) {
         if (mSideStagePosition == sideStagePosition) return;
         mSideStagePosition = sideStagePosition;
         sendOnStagePositionChanged();
 
-        if (mSideStageListener.mVisible && updateVisibility) {
-            onStageVisibilityChanged(mSideStageListener);
+        if (mSideStageListener.mVisible && updateBounds) {
+            onBoundsChanged(mSplitLayout);
         }
     }
 
@@ -275,6 +282,12 @@
         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 exitSplitScreen() {
         exitSplitScreen(null /* childrenToTop */);
     }
@@ -403,10 +416,20 @@
         // Divider is only visible if both the main stage and side stages are visible
         setDividerVisibility(isSplitScreenVisible());
 
-        if (mExitSplitScreenOnHide && !mainStageVisible && !sideStageVisible) {
-            // Exit split-screen if both stage are not visible.
-            // TODO: This is only a temporary request from UX and is likely to be removed soon...
-            exitSplitScreen();
+        if (!mainStageVisible && !sideStageVisible) {
+            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.
+            || (!mMainStage.mRootTaskInfo.isSleeping && !mSideStage.mRootTaskInfo.isSleeping)) {
+                exitSplitScreen();
+            }
+        } else if (mKeyguardOccluded) {
+            // At least one of the stages 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 : (sideStageVisible ? mSideStage : null);
+            exitSplitScreen(toTop);
         }
 
         if (mainStageVisible) {
@@ -580,11 +603,18 @@
     public void onDisplayAreaInfoChanged(DisplayAreaInfo displayAreaInfo) {
         mDisplayAreaInfo = displayAreaInfo;
         if (mSplitLayout != null
-                && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)) {
+                && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
+                && mMainStage.isActive()) {
             onBoundsChanged(mSplitLayout);
         }
     }
 
+    private void onFoldedStateChanged(boolean folded) {
+        if (folded && mMainStage.isActive()) {
+            exitSplitScreen(mMainStage);
+        }
+    }
+
     private Rect getSideStageBounds() {
         return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
                 ? mSplitLayout.getBounds1() : mSplitLayout.getBounds2();
@@ -672,7 +702,8 @@
     @Override
     public boolean startAnimation(@NonNull IBinder transition,
             @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         if (transition != mSplitTransitions.mPendingDismiss
                 && transition != mSplitTransitions.mPendingEnter) {
@@ -717,14 +748,14 @@
 
         boolean shouldAnimate = true;
         if (mSplitTransitions.mPendingEnter == transition) {
-            shouldAnimate = startPendingEnterAnimation(transition, info, t);
+            shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
         } else if (mSplitTransitions.mPendingDismiss == transition) {
-            shouldAnimate = startPendingDismissAnimation(transition, info, t);
+            shouldAnimate = startPendingDismissAnimation(transition, info, startTransaction);
         }
         if (!shouldAnimate) return false;
 
-        mSplitTransitions.playAnimation(transition, info, t, finishCallback,
-                mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
+        mSplitTransitions.playAnimation(transition, info, startTransaction, finishTransaction,
+                finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
         return true;
     }
 
@@ -754,7 +785,7 @@
 
             // Update local states (before animating).
             setDividerVisibility(true);
-            setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateVisibility */);
+            setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateBounds */);
             setSplitsVisible(true);
 
             addDividerBarToTransition(info, t, true /* show */);
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 c6fb5af..4eadf8c 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
@@ -16,6 +16,13 @@
 
 package com.android.wm.shell.transition;
 
+import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
+import static android.app.ActivityOptions.ANIM_CUSTOM;
+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.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
@@ -29,17 +36,28 @@
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
 import android.os.IBinder;
+import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.view.Choreographer;
 import android.view.SurfaceControl;
+import android.view.SurfaceSession;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.Transformation;
@@ -61,30 +79,53 @@
 public class DefaultTransitionHandler implements Transitions.TransitionHandler {
     private static final int MAX_ANIMATION_DURATION = 3000;
 
+    /**
+     * Restrict ability of activities overriding transition animation in a way such that
+     * an activity can do it only when the transition happens within a same task.
+     *
+     * @see android.app.Activity#overridePendingTransition(int, int)
+     */
+    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
+            "persist.wm.disable_custom_task_animation";
+
+    /**
+     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
+     */
+    static boolean sDisableCustomTaskAnimationProperty =
+            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
+
     private final TransactionPool mTransactionPool;
+    private final Context mContext;
     private final ShellExecutor mMainExecutor;
     private final ShellExecutor mAnimExecutor;
     private final TransitionAnimation mTransitionAnimation;
 
+    private final SurfaceSession mSurfaceSession = new SurfaceSession();
+
     /** Keeps track of the currently-running animations associated with each transition. */
     private final ArrayMap<IBinder, ArrayList<Animator>> mAnimations = new ArrayMap<>();
 
     private final Rect mInsets = new Rect(0, 0, 0, 0);
     private float mTransitionAnimationScaleSetting = 1.0f;
 
+    private final int mCurrentUserId;
+
     DefaultTransitionHandler(@NonNull TransactionPool transactionPool, Context context,
             @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
         mTransactionPool = transactionPool;
+        mContext = context;
         mMainExecutor = mainExecutor;
         mAnimExecutor = animExecutor;
         mTransitionAnimation = new TransitionAnimation(context, false /* debug */, Transitions.TAG);
+        mCurrentUserId = UserHandle.myUserId();
 
         AttributeCache.init(context);
     }
 
     @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                 "start default transition animation, info = %s", info);
@@ -100,16 +141,18 @@
             mAnimations.remove(transition);
             finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
         };
+
+        final int wallpaperTransit = getWallpaperTransitType(info);
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
             if (change.getMode() == TRANSIT_CHANGE) {
                 // No default animation for this, so just update bounds/position.
-                t.setPosition(change.getLeash(),
+                startTransaction.setPosition(change.getLeash(),
                         change.getEndAbsBounds().left - change.getEndRelOffset().x,
                         change.getEndAbsBounds().top - change.getEndRelOffset().y);
                 if (change.getTaskInfo() != null) {
                     // Skip non-tasks since those usually have null bounds.
-                    t.setWindowCrop(change.getLeash(),
+                    startTransaction.setWindowCrop(change.getLeash(),
                             change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
                 }
             }
@@ -117,12 +160,17 @@
             // Don't animate anything that isn't independent.
             if (!TransitionInfo.isIndependent(change, info)) continue;
 
-            Animation a = loadAnimation(info.getType(), info.getFlags(), change);
+            Animation a = loadAnimation(info, change, wallpaperTransit);
             if (a != null) {
-                startAnimInternal(animations, a, change.getLeash(), onAnimFinish);
+                startAnimInternal(animations, a, change.getLeash(), onAnimFinish,
+                        null /* position */);
+
+                if (info.getAnimationOptions() != null) {
+                    attachThumbnail(animations, onAnimFinish, change, info.getAnimationOptions());
+                }
             }
         }
-        t.apply();
+        startTransaction.apply();
         // run finish now in-case there are no animations
         onAnimFinish.run();
         return true;
@@ -141,68 +189,111 @@
     }
 
     @Nullable
-    private Animation loadAnimation(int type, int flags, TransitionInfo.Change change) {
-        // TODO(b/178678389): It should handle more type animation here
+    private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change,
+            int wallpaperTransit) {
         Animation a = null;
 
-        final boolean isOpening = Transitions.isOpeningType(type);
+        final int type = info.getType();
+        final int flags = info.getFlags();
         final int changeMode = change.getMode();
         final int changeFlags = change.getFlags();
+        final boolean isOpeningType = Transitions.isOpeningType(type);
+        final boolean enter = Transitions.isOpeningType(changeMode);
+        final boolean isTask = change.getTaskInfo() != null;
+        final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
+        final int overrideType = options != null ? options.getType() : ANIM_NONE;
+        final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true;
 
         if (type == TRANSIT_RELAUNCH) {
             a = mTransitionAnimation.createRelaunchAnimation(
-                    change.getStartAbsBounds(), mInsets, change.getEndAbsBounds());
+                    change.getEndAbsBounds(), mInsets, change.getEndAbsBounds());
         } else if (type == TRANSIT_KEYGUARD_GOING_AWAY) {
             a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
                     (changeFlags & FLAG_SHOW_WALLPAPER) != 0);
         } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
             a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
-        } else if (changeMode == TRANSIT_OPEN && isOpening) {
-            if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
-                // This received a transferred starting window, so don't animate
-                return null;
-            }
-
-            if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
-                a = mTransitionAnimation.loadVoiceActivityOpenAnimation(true /** enter */);
-            } else if (change.getTaskInfo() != null) {
-                a = mTransitionAnimation.loadDefaultAnimationAttr(
-                        R.styleable.WindowAnimation_taskOpenEnterAnimation);
+        } else if (overrideType == ANIM_CUSTOM
+                && (canCustomContainer || options.getOverrideTaskTransition())) {
+            a = mTransitionAnimation.loadAnimationRes(options.getPackageName(), enter
+                    ? options.getEnterResId() : options.getExitResId());
+        } else if (overrideType == ANIM_OPEN_CROSS_PROFILE_APPS && enter) {
+            a = mTransitionAnimation.loadCrossProfileAppEnterAnimation();
+        } else if (overrideType == ANIM_CLIP_REVEAL) {
+            a = mTransitionAnimation.createClipRevealAnimationLocked(type, wallpaperTransit, enter,
+                    change.getEndAbsBounds(), change.getEndAbsBounds(),
+                    options.getTransitionBounds());
+        } else if (overrideType == ANIM_SCALE_UP) {
+            a = mTransitionAnimation.createScaleUpAnimationLocked(type, wallpaperTransit, enter,
+                    change.getEndAbsBounds(), options.getTransitionBounds());
+        } else if (overrideType == ANIM_THUMBNAIL_SCALE_UP
+                || overrideType == ANIM_THUMBNAIL_SCALE_DOWN) {
+            final boolean scaleUp = overrideType == ANIM_THUMBNAIL_SCALE_UP;
+            a = mTransitionAnimation.createThumbnailEnterExitAnimationLocked(enter, scaleUp,
+                    change.getEndAbsBounds(), type, wallpaperTransit, options.getThumbnail(),
+                    options.getTransitionBounds());
+        } 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 ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
+            if (isOpeningType) {
+                a = mTransitionAnimation.loadVoiceActivityOpenAnimation(enter);
             } else {
-                a = mTransitionAnimation.loadDefaultAnimationRes(
-                        (changeFlags & FLAG_TRANSLUCENT) == 0
-                        ? R.anim.activity_open_enter : R.anim.activity_translucent_open_enter);
+                a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter);
             }
-        } else if (changeMode == TRANSIT_TO_FRONT && isOpening) {
-            if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
-                // This received a transferred starting window, so don't animate
-                return null;
-            }
-
-            if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
-                a = mTransitionAnimation.loadVoiceActivityOpenAnimation(true /** enter */);
+        } else if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0 && isOpeningType) {
+            // This received a transferred starting window, so don't animate
+            return null;
+        } else if (type == TRANSIT_OPEN) {
+            if (isTask) {
+                a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+                        ? R.styleable.WindowAnimation_taskOpenEnterAnimation
+                        : R.styleable.WindowAnimation_taskOpenExitAnimation);
             } else {
-                a = mTransitionAnimation.loadDefaultAnimationAttr(
-                        R.styleable.WindowAnimation_taskToFrontEnterAnimation);
+                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
+                    a = mTransitionAnimation.loadDefaultAnimationRes(
+                            R.anim.activity_translucent_open_enter);
+                } else {
+                    a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+                            ? R.styleable.WindowAnimation_activityOpenEnterAnimation
+                            : R.styleable.WindowAnimation_activityOpenExitAnimation);
+                }
             }
-        } else if (changeMode == TRANSIT_CLOSE && !isOpening) {
-            if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
-                a = mTransitionAnimation.loadVoiceActivityExitAnimation(false /** enter */);
-            } else if (change.getTaskInfo() != null) {
-                a = mTransitionAnimation.loadDefaultAnimationAttr(
-                        R.styleable.WindowAnimation_taskCloseExitAnimation);
+        } 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 {
-                a = mTransitionAnimation.loadDefaultAnimationRes(
-                        (changeFlags & FLAG_TRANSLUCENT) == 0
-                        ? R.anim.activity_close_exit : R.anim.activity_translucent_close_exit);
+                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
+                    a = mTransitionAnimation.loadDefaultAnimationRes(
+                            R.anim.activity_translucent_close_exit);
+                } else {
+                    a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+                            ? R.styleable.WindowAnimation_activityCloseEnterAnimation
+                            : R.styleable.WindowAnimation_activityCloseExitAnimation);
+                }
             }
-        } else if (changeMode == TRANSIT_TO_BACK && !isOpening) {
-            if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
-                a = mTransitionAnimation.loadVoiceActivityExitAnimation(false /** enter */);
-            } else {
-                a = mTransitionAnimation.loadDefaultAnimationAttr(
-                        R.styleable.WindowAnimation_taskToBackExitAnimation);
-            }
+        } else if (type == TRANSIT_TO_BACK) {
+            a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+                    ? R.styleable.WindowAnimation_taskToBackEnterAnimation
+                    : R.styleable.WindowAnimation_taskToBackExitAnimation);
         } else if (changeMode == TRANSIT_CHANGE) {
             // In the absence of a specific adapter, we just want to keep everything stationary.
             a = new AlphaAnimation(1.f, 1.f);
@@ -210,17 +301,19 @@
         }
 
         if (a != null) {
-            Rect start = change.getStartAbsBounds();
-            Rect end = change.getEndAbsBounds();
+            if (!a.isInitialized()) {
+                Rect end = change.getEndAbsBounds();
+                a.initialize(end.width(), end.height(), end.width(), end.height());
+            }
             a.restrictDuration(MAX_ANIMATION_DURATION);
-            a.initialize(end.width(), end.height(), start.width(), start.height());
             a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         }
         return a;
     }
 
     private void startAnimInternal(@NonNull ArrayList<Animator> animations, @NonNull Animation anim,
-            @NonNull SurfaceControl leash, @NonNull Runnable finishCallback) {
+            @NonNull SurfaceControl leash, @NonNull Runnable finishCallback,
+            @Nullable Point position) {
         final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
         final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
         final Transformation transformation = new Transformation();
@@ -231,11 +324,13 @@
         va.addUpdateListener(animation -> {
             final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
 
-            applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix);
+            applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
+                    position);
         });
 
         final Runnable finisher = () -> {
-            applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix);
+            applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
+                    position);
 
             mTransactionPool.release(transaction);
             mMainExecutor.execute(() -> {
@@ -258,9 +353,112 @@
         mAnimExecutor.execute(va::start);
     }
 
+    private void attachThumbnail(@NonNull ArrayList<Animator> animations,
+            @NonNull Runnable finishCallback, TransitionInfo.Change change,
+            TransitionInfo.AnimationOptions options) {
+        final boolean isTask = change.getTaskInfo() != null;
+        final boolean isOpen = Transitions.isOpeningType(change.getMode());
+        final boolean isClose = Transitions.isClosingType(change.getMode());
+        if (isOpen) {
+            if (options.getType() == ANIM_OPEN_CROSS_PROFILE_APPS && isTask) {
+                attachCrossProfileThunmbnailAnimation(animations, finishCallback, change);
+            } else if (options.getType() == ANIM_THUMBNAIL_SCALE_UP) {
+                attachThumbnailAnimation(animations, finishCallback, change, options);
+            }
+        } else if (isClose && options.getType() == ANIM_THUMBNAIL_SCALE_DOWN) {
+            attachThumbnailAnimation(animations, finishCallback, change, options);
+        }
+    }
+
+    private void attachCrossProfileThunmbnailAnimation(@NonNull ArrayList<Animator> animations,
+            @NonNull Runnable finishCallback, TransitionInfo.Change change) {
+        final int thumbnailDrawableRes = change.getTaskInfo().userId == mCurrentUserId
+                ? R.drawable.ic_account_circle : R.drawable.ic_corp_badge;
+        final Rect bounds = change.getEndAbsBounds();
+        final HardwareBuffer thumbnail = mTransitionAnimation.createCrossProfileAppsThumbnail(
+                thumbnailDrawableRes, bounds);
+        if (thumbnail == null) {
+            return;
+        }
+
+        final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+        final WindowThumbnail wt = WindowThumbnail.createAndAttach(mSurfaceSession,
+                change.getLeash(), thumbnail, transaction);
+        final Animation a =
+                mTransitionAnimation.createCrossProfileAppsThumbnailAnimationLocked(bounds);
+        if (a == null) {
+            return;
+        }
+
+        final Runnable finisher = () -> {
+            wt.destroy(transaction);
+            mTransactionPool.release(transaction);
+
+            finishCallback.run();
+        };
+        a.restrictDuration(MAX_ANIMATION_DURATION);
+        a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+        startAnimInternal(animations, a, wt.getSurface(), finisher,
+                new Point(bounds.left, bounds.top));
+    }
+
+    private void attachThumbnailAnimation(@NonNull ArrayList<Animator> animations,
+            @NonNull Runnable finishCallback, TransitionInfo.Change change,
+            TransitionInfo.AnimationOptions options) {
+        final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+        final WindowThumbnail wt = WindowThumbnail.createAndAttach(mSurfaceSession,
+                change.getLeash(), options.getThumbnail(), transaction);
+        final Rect bounds = change.getEndAbsBounds();
+        final int orientation = mContext.getResources().getConfiguration().orientation;
+        final Animation a = mTransitionAnimation.createThumbnailAspectScaleAnimationLocked(bounds,
+                mInsets, options.getThumbnail(), orientation, null /* startRect */,
+                options.getTransitionBounds(), options.getType() == ANIM_THUMBNAIL_SCALE_UP);
+
+        final Runnable finisher = () -> {
+            wt.destroy(transaction);
+            mTransactionPool.release(transaction);
+
+            finishCallback.run();
+        };
+        a.restrictDuration(MAX_ANIMATION_DURATION);
+        a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+        startAnimInternal(animations, a, wt.getSurface(), finisher, null /* position */);
+    }
+
+    private static int getWallpaperTransitType(TransitionInfo info) {
+        boolean hasOpenWallpaper = false;
+        boolean hasCloseWallpaper = false;
+
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            if ((change.getFlags() & FLAG_SHOW_WALLPAPER) != 0) {
+                if (Transitions.isOpeningType(change.getMode())) {
+                    hasOpenWallpaper = true;
+                } else if (Transitions.isClosingType(change.getMode())) {
+                    hasCloseWallpaper = true;
+                }
+            }
+        }
+
+        if (hasOpenWallpaper && hasCloseWallpaper) {
+            return Transitions.isOpeningType(info.getType())
+                    ? WALLPAPER_TRANSITION_INTRA_OPEN : WALLPAPER_TRANSITION_INTRA_CLOSE;
+        } else if (hasOpenWallpaper) {
+            return WALLPAPER_TRANSITION_OPEN;
+        } else if (hasCloseWallpaper) {
+            return WALLPAPER_TRANSITION_CLOSE;
+        } else {
+            return WALLPAPER_TRANSITION_NONE;
+        }
+    }
+
     private static void applyTransformation(long time, SurfaceControl.Transaction t,
-            SurfaceControl leash, Animation anim, Transformation transformation, float[] matrix) {
+            SurfaceControl leash, Animation anim, Transformation transformation, float[] matrix,
+            Point position) {
         anim.getTransformation(time, transformation);
+        if (position != null) {
+            transformation.getMatrix().postTranslate(position.x, position.y);
+        }
         t.setMatrix(leash, transformation.getMatrix(), matrix);
         t.setAlpha(leash, transformation.getAlpha());
         t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 4da6664..6bd8053 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -57,7 +57,8 @@
 
     @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         if (mTransition != transition) return false;
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Using registered One-shot remote"
@@ -70,19 +71,24 @@
         };
         IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
             @Override
-            public void onTransitionFinished(WindowContainerTransaction wct) {
+            public void onTransitionFinished(WindowContainerTransaction wct,
+                    SurfaceControl.Transaction sct) {
                 if (mRemote.asBinder() != null) {
                     mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
                 }
-                mMainExecutor.execute(
-                        () -> finishCallback.onTransitionFinished(wct, null /* wctCB */));
+                mMainExecutor.execute(() -> {
+                    if (sct != null) {
+                        finishTransaction.merge(sct);
+                    }
+                    finishCallback.onTransitionFinished(wct, null /* wctCB */);
+                });
             }
         };
         try {
             if (mRemote.asBinder() != null) {
                 mRemote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
             }
-            mRemote.startAnimation(transition, info, t, cb);
+            mRemote.startAnimation(transition, info, startTransaction, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error running remote transition.", e);
             if (mRemote.asBinder() != null) {
@@ -102,7 +108,8 @@
 
         IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
             @Override
-            public void onTransitionFinished(WindowContainerTransaction wct) {
+            public void onTransitionFinished(WindowContainerTransaction wct,
+                    SurfaceControl.Transaction sct) {
                 mMainExecutor.execute(
                         () -> finishCallback.onTransitionFinished(wct, null /* wctCB */));
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index 9bfb261..f432049 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -56,14 +56,7 @@
     private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
             new ArrayList<>();
 
-    private final IBinder.DeathRecipient mTransitionDeathRecipient =
-            new IBinder.DeathRecipient() {
-                @Override
-                @BinderThread
-                public void binderDied() {
-                    mMainExecutor.execute(() -> mFilters.clear());
-                }
-            };
+    private final ArrayMap<IBinder, RemoteDeathHandler> mDeathHandlers = new ArrayMap<>();
 
     RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
@@ -71,7 +64,9 @@
 
     void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
         try {
-            remote.asBinder().linkToDeath(mTransitionDeathRecipient, 0 /* flags */);
+            RemoteDeathHandler handler = new RemoteDeathHandler(remote.asBinder());
+            remote.asBinder().linkToDeath(handler, 0 /* flags */);
+            mDeathHandlers.put(remote.asBinder(), handler);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to link to death");
             return;
@@ -88,7 +83,8 @@
             }
         }
         if (removed) {
-            remote.asBinder().unlinkToDeath(mTransitionDeathRecipient, 0 /* flags */);
+            RemoteDeathHandler handler = mDeathHandlers.remove(remote.asBinder());
+            remote.asBinder().unlinkToDeath(handler, 0 /* flags */);
         }
     }
 
@@ -99,7 +95,8 @@
 
     @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction t,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         IRemoteTransition pendingRemote = mRequestedRemotes.get(transition);
         if (pendingRemote == null) {
@@ -132,11 +129,15 @@
         };
         IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
             @Override
-            public void onTransitionFinished(WindowContainerTransaction wct) {
+            public void onTransitionFinished(WindowContainerTransaction wct,
+                    SurfaceControl.Transaction sct) {
                 if (remote.asBinder() != null) {
                     remote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
                 }
                 mMainExecutor.execute(() -> {
+                    if (sct != null) {
+                        finishTransaction.merge(sct);
+                    }
                     mRequestedRemotes.remove(transition);
                     finishCallback.onTransitionFinished(wct, null /* wctCB */);
                 });
@@ -146,7 +147,7 @@
             if (remote.asBinder() != null) {
                 remote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
             }
-            remote.startAnimation(transition, info, t, cb);
+            remote.startAnimation(transition, info, startTransaction, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error running remote transition.", e);
             if (remote.asBinder() != null) {
@@ -170,7 +171,8 @@
 
         IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
             @Override
-            public void onTransitionFinished(WindowContainerTransaction wct) {
+            public void onTransitionFinished(WindowContainerTransaction wct,
+                    SurfaceControl.Transaction sct) {
                 mMainExecutor.execute(() -> {
                     if (!mRequestedRemotes.containsKey(mergeTarget)) {
                         Log.e(TAG, "Merged transition finished after it's mergeTarget (the "
@@ -200,4 +202,25 @@
                 + " for %s: %s", transition, remote);
         return new WindowContainerTransaction();
     }
+
+    /** NOTE: binder deaths can alter the filter order */
+    private class RemoteDeathHandler implements IBinder.DeathRecipient {
+        private final IBinder mRemote;
+
+        RemoteDeathHandler(IBinder remote) {
+            mRemote = remote;
+        }
+
+        @Override
+        @BinderThread
+        public void binderDied() {
+            mMainExecutor.execute(() -> {
+                for (int i = mFilters.size() - 1; i >= 0; --i) {
+                    if (mRemote.equals(mFilters.get(i).second.asBinder())) {
+                        mFilters.remove(i);
+                    }
+                }
+            });
+        }
+    }
 }
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 60707cc..8ed92df 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
@@ -77,6 +77,12 @@
     /** 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;
+
+    /** 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;
+
     private final WindowOrganizer mOrganizer;
     private final Context mContext;
     private final ShellExecutor mMainExecutor;
@@ -382,7 +388,7 @@
     }
 
     boolean startAnimation(@NonNull ActiveTransition active, TransitionHandler handler) {
-        return handler.startAnimation(active.mToken, active.mInfo, active.mStartT,
+        return handler.startAnimation(active.mToken, active.mInfo, active.mStartT, active.mFinishT,
                 (wct, cb) -> onFinish(active.mToken, wct, cb));
     }
 
@@ -566,12 +572,19 @@
          * Starts a transition animation. This is always called if handleRequest returned non-null
          * for a particular transition. Otherwise, it is only called if no other handler before
          * it handled the transition.
-         *
+         * @param startTransaction the transaction given to the handler to be applied before the
+         *                         transition animation. Note the handler is expected to call on
+         *                         {@link SurfaceControl.Transaction#apply()} for startTransaction.
+         * @param finishTransaction the transaction given to the handler to be applied after the
+         *                       transition animation. Unlike startTransaction, the handler is NOT
+         *                       expected to apply this transaction. The Transition system will
+         *                       apply it when finishCallback is called.
          * @param finishCallback Call this when finished. This MUST be called on main thread.
          * @return true if transition was handled, false if not (falls-back to default).
          */
         boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-                @NonNull SurfaceControl.Transaction t,
+                @NonNull SurfaceControl.Transaction startTransaction,
+                @NonNull SurfaceControl.Transaction finishTransaction,
                 @NonNull TransitionFinishCallback finishCallback);
 
         /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/WindowThumbnail.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/WindowThumbnail.java
new file mode 100644
index 0000000..2c668ed
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/WindowThumbnail.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.transition;
+
+import android.graphics.ColorSpace;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+/**
+ * Represents a surface that is displayed over a transition surface.
+ */
+class WindowThumbnail {
+
+    private SurfaceControl mSurfaceControl;
+
+    private WindowThumbnail() {}
+
+    /** Create a thumbnail surface and attach it over a parent surface. */
+    static WindowThumbnail createAndAttach(SurfaceSession surfaceSession, SurfaceControl parent,
+            HardwareBuffer thumbnailHeader, SurfaceControl.Transaction t) {
+        WindowThumbnail windowThumbnail = new WindowThumbnail();
+        windowThumbnail.mSurfaceControl = new SurfaceControl.Builder(surfaceSession)
+                .setParent(parent)
+                .setName("WindowThumanil : " + parent.toString())
+                .setCallsite("WindowThumanil")
+                .setFormat(PixelFormat.TRANSLUCENT)
+                .build();
+
+        GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(thumbnailHeader);
+        t.setBuffer(windowThumbnail.mSurfaceControl, graphicBuffer);
+        t.setColorSpace(windowThumbnail.mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
+        t.setLayer(windowThumbnail.mSurfaceControl, Integer.MAX_VALUE);
+        t.show(windowThumbnail.mSurfaceControl);
+        t.apply();
+
+        return windowThumbnail;
+    }
+
+    SurfaceControl getSurface() {
+        return mSurfaceControl;
+    }
+
+    /** Remove the thumbnail surface and release the surface. */
+    void destroy(SurfaceControl.Transaction t) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+
+        t.remove(mSurfaceControl);
+        t.apply();
+        mSurfaceControl.release();
+        mSurfaceControl = null;
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 9dd25fe..3ca5b9c 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -25,11 +25,17 @@
 
 android_test {
     name: "WMShellFlickerTests",
-    srcs: ["src/**/*.java", "src/**/*.kt"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
     manifest: "AndroidManifest.xml",
     test_config: "AndroidTest.xml",
     platform_apis: true,
     certificate: "platform",
+    optimize: {
+        enabled: false,
+    },
     test_suites: ["device-tests"],
     libs: ["android.test.runner"],
     static_libs: [
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 ef9f742..e1e32ab 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -61,7 +60,7 @@
                 // TODO pair apps through normal UX flow
                 executeShellCommand(
                     composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
-                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+                nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
             }
         }
 
@@ -87,8 +86,8 @@
 
     @FlakyTest
     @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
     }
 
     @Presubmit
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 db63c4c..3ecab8c 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -29,6 +28,7 @@
 import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,7 +54,7 @@
                 // TODO pair apps through normal UX flow
                 executeShellCommand(
                     composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
-                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+                waitAppsShown(primaryApp, secondaryApp)
             }
         }
 
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 c8d3423..42bb359 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -61,7 +60,7 @@
                 // TODO pair apps through normal UX flow
                 executeShellCommand(
                         composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
-                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+                nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
             }
         }
 
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 83df836..7820c8c 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
@@ -29,6 +29,7 @@
 import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
 import com.android.wm.shell.flicker.appPairsDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,9 +52,11 @@
         get() = {
             super.transition(this, it)
             setup {
-                executeShellCommand(
-                    composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
-                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+                eachRun {
+                    executeShellCommand(
+                            composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
+                    waitAppsShown(primaryApp, secondaryApp)
+                }
             }
             transitions {
                 // TODO pair apps through normal UX flow
@@ -107,8 +110,8 @@
 
     @FlakyTest
     @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
     }
 
     companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 1935bb9..cdf89a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -30,14 +30,14 @@
 import com.android.server.wm.flicker.helpers.isRotated
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
 import com.android.wm.shell.flicker.helpers.BaseAppHelper
 import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
@@ -154,26 +154,26 @@
 
     @FlakyTest(bugId = 186510496)
     @Test
-    open fun navBarLayerIsAlwaysVisible() {
-        testSpec.navBarLayerIsAlwaysVisible()
+    open fun navBarLayerIsVisible() {
+        testSpec.navBarLayerIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun statusBarLayerIsAlwaysVisible() {
-        testSpec.statusBarLayerIsAlwaysVisible()
+    open fun statusBarLayerIsVisible() {
+        testSpec.statusBarLayerIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun navBarWindowIsAlwaysVisible() {
-        testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsVisible() {
+        testSpec.navBarWindowIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() {
-        testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsVisible() {
+        testSpec.statusBarWindowIsVisible()
     }
 
     @Presubmit
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 c875c00..3da1e8a 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -31,7 +30,7 @@
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
 import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -57,15 +56,15 @@
             transitions {
                 executeShellCommand(composePairsCommand(
                     primaryTaskId, secondaryTaskId, true /* pair */))
-                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+                waitAppsShown(primaryApp, secondaryApp)
                 setRotation(testSpec.config.endRotation)
             }
         }
 
     @FlakyTest
     @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        super.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsVisible() {
+        super.statusBarLayerIsVisible()
     }
 
     @Presubmit
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 c3360ca..a5fc8ae 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
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -28,12 +27,12 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
 import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -60,7 +59,7 @@
                 this.setRotation(testSpec.config.endRotation)
                 executeShellCommand(
                     composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
-                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+                waitAppsShown(primaryApp, secondaryApp)
             }
         }
 
@@ -70,16 +69,16 @@
 
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
 
     @FlakyTest
     @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        super.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsVisible() {
+        super.statusBarLayerIsVisible()
     }
 
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 512fd9a..cc861f9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -37,8 +37,8 @@
                 test {
                     device.wakeUpAndGoToHomeScreen()
                     this.setRotation(Surface.ROTATION_0)
-                    primaryApp.launchViaIntent()
-                    secondaryApp.launchViaIntent()
+                    primaryApp.launchViaIntent(wmHelper)
+                    secondaryApp.launchViaIntent(wmHelper)
                     updateTasksId()
                 }
             }
@@ -54,8 +54,8 @@
 
     @FlakyTest
     @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
     }
 
     @FlakyTest
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 5b8cfb8..5a438af 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
@@ -19,6 +19,7 @@
 import android.app.Instrumentation
 import android.content.ComponentName
 import android.graphics.Region
+import com.android.server.wm.flicker.Flicker
 import com.android.server.wm.flicker.helpers.WindowUtils
 
 class AppPairsHelper(
@@ -43,5 +44,17 @@
     companion object {
         const val TEST_REPETITIONS = 1
         const val TIMEOUT_MS = 3_000L
+
+        fun Flicker.waitAppsShown(app1: SplitScreenHelper?, app2: SplitScreenHelper?) {
+            wmHelper.waitFor("primaryAndSecondaryAppsVisible") { dump ->
+                val primaryAppVisible = app1?.let {
+                    dump.wmState.isWindowSurfaceShown(app1.defaultWindowName)
+                } ?: false
+                val secondaryAppVisible = app2?.let {
+                    dump.wmState.isWindowSurfaceShown(app2.defaultWindowName)
+                } ?: false
+                primaryAppVisible && secondaryAppVisible
+            }
+        }
     }
 }
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 f4dd7de..d4b4e5d 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
@@ -62,7 +62,7 @@
         stringExtras: Map<String, String>
     ) {
         super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
-        wmHelper.waitFor { it.wmState.hasPipWindow() }
+        wmHelper.waitFor("hasPipWindow") { it.wmState.hasPipWindow() }
     }
 
     private fun focusOnObject(selector: BySelector): Boolean {
@@ -84,7 +84,7 @@
         clickObject(ENTER_PIP_BUTTON_ID)
 
         // Wait on WMHelper or simply wait for 3 seconds
-        wmHelper?.waitFor { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
+        wmHelper?.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
     }
 
     fun clickStartMediaSessionButton() {
@@ -137,7 +137,7 @@
         }
 
         // Wait for animation to complete.
-        wmHelper.waitFor { !it.wmState.hasPipWindow() }
+        wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
         wmHelper.waitForHomeActivityVisible()
     }
 
@@ -167,7 +167,7 @@
         val windowRect = windowRegion.bounds
         uiDevice.click(windowRect.centerX(), windowRect.centerY())
         uiDevice.click(windowRect.centerX(), windowRect.centerY())
-        wmHelper.waitFor { !it.wmState.hasPipWindow() }
+        wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
         wmHelper.waitForAppTransitionIdle()
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index 4f12f2b..c67b714 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -26,9 +26,9 @@
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
@@ -77,11 +77,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index 85ded8a..2c98ae4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -27,9 +27,9 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
@@ -89,11 +89,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index bad4683..c26f99f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -29,8 +29,8 @@
 import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -87,11 +87,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 76dcd8b..fe931d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -29,8 +29,8 @@
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -91,11 +91,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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 a4d2ab5..c6ea9db 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
@@ -33,14 +33,14 @@
 import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
 import com.android.wm.shell.flicker.helpers.SimpleAppHelper
@@ -96,15 +96,15 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
@@ -122,7 +122,7 @@
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 05eb5f4..69b0c86 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -31,7 +31,7 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -77,7 +77,7 @@
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index 3e83b63..781ccb3 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
@@ -34,14 +34,14 @@
 import com.android.server.wm.flicker.helpers.resizeSplitScreen
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.flicker.traces.layers.getVisibleBounds
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
 import com.android.wm.shell.flicker.helpers.SimpleAppHelper
@@ -101,10 +101,10 @@
         }
 
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @FlakyTest(bugId = 156223549)
     @Test
@@ -123,10 +123,10 @@
     }
 
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation)
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 58482ea..5c313f6 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
@@ -30,10 +30,10 @@
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -88,11 +88,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @FlakyTest
     @Test
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 06828d6..1970e9a 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
@@ -30,10 +30,10 @@
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -85,11 +85,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @FlakyTest
     @Test
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 f8e32bf..fdf690f 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
@@ -31,10 +31,10 @@
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
@@ -100,11 +100,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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 cb246ca..a9d873f2 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
@@ -31,10 +31,10 @@
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
@@ -107,11 +107,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
index 2a66074..1e14e88 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
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 b6af260..80fedd4 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
@@ -44,7 +44,7 @@
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
             transitions {
-                pipApp.clickEnterPipButton()
+                pipApp.clickEnterPipButton(wmHelper)
                 pipApp.expandPipWindow(wmHelper)
             }
         }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
index 524a1b4..7de1378 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -56,19 +56,19 @@
 
     @Presubmit
     @Test
-    override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
 
     @FlakyTest
     @Test
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 6833b96..e674c9f 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
@@ -100,11 +100,11 @@
 
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
@@ -125,11 +125,11 @@
 
     @Presubmit
     @Test
-    override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
 
     companion object {
         const val TEST_REPETITIONS = 2
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index b4c75a6..bde7613 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -29,16 +29,16 @@
 import com.android.server.wm.flicker.helpers.isRotated
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.wm.shell.flicker.helpers.PipAppHelper
 import com.android.wm.shell.flicker.testapp.Components
 import org.junit.Test
@@ -162,19 +162,19 @@
 
     @Presubmit
     @Test
-    open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @FlakyTest
     @Test
-    open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    open fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @FlakyTest
     @Test
-    open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    open fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index 20ac5bf..1cbad15 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -47,6 +47,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.SyncTransactionQueue.TransactionRunnable;
 
 import org.junit.After;
 import org.junit.Before;
@@ -71,6 +73,8 @@
     ShellTaskOrganizer mOrganizer;
     @Mock
     HandlerExecutor mExecutor;
+    @Mock
+    SyncTransactionQueue mSyncQueue;
 
     SurfaceSession mSession;
     SurfaceControl mLeash;
@@ -99,7 +103,14 @@
         }).when(mExecutor).execute(any());
 
         when(mOrganizer.getExecutor()).thenReturn(mExecutor);
-        mTaskView = new TaskView(mContext, mOrganizer);
+
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            final TransactionRunnable r = invocationOnMock.getArgument(0);
+            r.runWithTransaction(new SurfaceControl.Transaction());
+            return null;
+        }).when(mSyncQueue).runInSync(any());
+
+        mTaskView = new TaskView(mContext, mOrganizer, mSyncQueue);
         mTaskView.setListener(mExecutor, mViewListener);
     }
 
@@ -112,7 +123,7 @@
 
     @Test
     public void testSetPendingListener_throwsException() {
-        TaskView taskView = new TaskView(mContext, mOrganizer);
+        TaskView taskView = new TaskView(mContext, mOrganizer, mSyncQueue);
         taskView.setListener(mExecutor, mViewListener);
         try {
             taskView.setListener(mExecutor, mViewListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 952dc31..e138595 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -61,7 +61,7 @@
         mSplitLayout = new SplitLayout(
                 "TestSplitLayout",
                 mContext,
-                getConfiguration(false),
+                getConfiguration(),
                 mSplitLayoutHandler,
                 b -> b.setParent(mRootLeash),
                 mDisplayImeController,
@@ -71,9 +71,22 @@
     @Test
     @UiThreadTest
     public void testUpdateConfiguration() {
-        mSplitLayout.init();
-        assertThat(mSplitLayout.updateConfiguration(getConfiguration(false))).isFalse();
-        assertThat(mSplitLayout.updateConfiguration(getConfiguration(true))).isTrue();
+        final Configuration config = getConfiguration();
+
+        // Verify it returns true if new config won't affect split layout.
+        assertThat(mSplitLayout.updateConfiguration(config)).isFalse();
+
+        // Verify updateConfiguration returns true if the orientation changed.
+        config.orientation = ORIENTATION_LANDSCAPE;
+        assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
+
+        // Verify updateConfiguration returns true if it rotated.
+        config.windowConfiguration.setRotation(1);
+        assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
+
+        // Verify updateConfiguration returns true if the root bounds changed.
+        config.windowConfiguration.setBounds(new Rect(0, 0, 2160, 1080));
+        assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
     }
 
     @Test
@@ -108,12 +121,13 @@
         verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true));
     }
 
-    private static Configuration getConfiguration(boolean isLandscape) {
+    private static Configuration getConfiguration() {
         final Configuration configuration = new Configuration();
         configuration.unset();
-        configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+        configuration.orientation = ORIENTATION_PORTRAIT;
+        configuration.windowConfiguration.setRotation(0);
         configuration.windowConfiguration.setBounds(
-                new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
+                new Rect(0, 0, 1080, 2160));
         return configuration;
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 9d7c82b..0270093 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -79,6 +79,7 @@
     @Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
     private TestShellExecutor mMainExecutor;
     private PipBoundsState mPipBoundsState;
+    private PipTransitionState mPipTransitionState;
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
 
     private ComponentName mComponent1;
@@ -90,11 +91,12 @@
         mComponent1 = new ComponentName(mContext, "component1");
         mComponent2 = new ComponentName(mContext, "component2");
         mPipBoundsState = new PipBoundsState(mContext);
+        mPipTransitionState = new PipTransitionState();
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
                 new PipSnapAlgorithm());
         mMainExecutor = new TestShellExecutor();
         mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext,
-                mMockSyncTransactionQueue, mPipBoundsState,
+                mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
                 mPipBoundsAlgorithm, mMockPhonePipMenuController,
                 mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
                 mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
index 56a0056..69ead3a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
@@ -33,6 +33,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
@@ -46,7 +47,7 @@
 /** Tests for {@link SideStage} */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class SideStageTests {
+public class SideStageTests extends ShellTestCase {
     @Mock private ShellTaskOrganizer mTaskOrganizer;
     @Mock private StageTaskListener.StageListenerCallbacks mCallbacks;
     @Mock private SyncTransactionQueue mSyncQueue;
@@ -60,8 +61,8 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mRootTask = new TestRunningTaskInfoBuilder().build();
-        mSideStage = new SideStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue,
-                mSurfaceSession);
+        mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
+                mSyncQueue, mSurfaceSession);
         mSideStage.onTaskAppeared(mRootTask, mRootLeash);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index aca80f3..b6da868 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -102,7 +102,7 @@
         mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mock(
                 StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
         mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
-        mSideStage = new SideStage(mTaskOrganizer, DEFAULT_DISPLAY, mock(
+        mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
                 StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
         mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
@@ -131,6 +131,7 @@
         mSideStage.onTaskAppeared(mSideChild, createMockSurface());
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         assertTrue(accepted);
 
@@ -168,6 +169,7 @@
         mSideStage.onTaskAppeared(newTask, createMockSurface());
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         assertFalse(accepted);
         assertTrue(mStageCoordinator.isSplitScreenVisible());
@@ -188,6 +190,7 @@
         mSideStage.onTaskVanished(newTask);
         accepted = mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         assertFalse(accepted);
         assertTrue(mStageCoordinator.isSplitScreenVisible());
@@ -223,6 +226,7 @@
         mSideStage.onTaskVanished(mSideChild);
         mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         assertFalse(mStageCoordinator.isSplitScreenVisible());
     }
@@ -244,6 +248,7 @@
         mSideStage.onTaskVanished(mSideChild);
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         assertTrue(accepted);
         assertFalse(mStageCoordinator.isSplitScreenVisible());
@@ -274,6 +279,7 @@
         mSideStage.onTaskVanished(mSideChild);
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         assertTrue(accepted);
         assertFalse(mStageCoordinator.isSplitScreenVisible());
@@ -298,6 +304,7 @@
         mSideStage.onTaskAppeared(mSideChild, createMockSurface());
         mStageCoordinator.startAnimation(enterTransit, enterInfo,
                 mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
                 mock(Transitions.TransitionFinishCallback.class));
         mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction());
     }
@@ -335,10 +342,11 @@
 
         @Override
         public void startAnimation(IBinder transition, TransitionInfo info,
-                SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+                SurfaceControl.Transaction startTransaction,
+                IRemoteTransitionFinishedCallback finishCallback)
                 throws RemoteException {
             mCalled = true;
-            finishCallback.onTransitionFinished(mRemoteFinishWCT);
+            finishCallback.onTransitionFinished(mRemoteFinishWCT, null /* sct */);
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 2d2ab2c..a2b1f64 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -127,11 +127,13 @@
         TestTransitionHandler testHandler = new TestTransitionHandler() {
             @Override
             public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-                    @NonNull SurfaceControl.Transaction t,
+                    @NonNull SurfaceControl.Transaction startTransaction,
+                    @NonNull SurfaceControl.Transaction finishTransaction,
                     @NonNull Transitions.TransitionFinishCallback finishCallback) {
                 for (TransitionInfo.Change chg : info.getChanges()) {
                     if (chg.getMode() == TRANSIT_CHANGE) {
-                        return super.startAnimation(transition, info, t, finishCallback);
+                        return super.startAnimation(transition, info, startTransaction,
+                                finishTransaction, finishCallback);
                     }
                 }
                 return false;
@@ -211,7 +213,7 @@
                     SurfaceControl.Transaction t,
                     IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
                 remoteCalled[0] = true;
-                finishCallback.onTransitionFinished(remoteFinishWCT);
+                finishCallback.onTransitionFinished(remoteFinishWCT, null /* sct */);
             }
 
             @Override
@@ -285,7 +287,7 @@
                     SurfaceControl.Transaction t,
                     IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
                 remoteCalled[0] = true;
-                finishCallback.onTransitionFinished(null /* wct */);
+                finishCallback.onTransitionFinished(null /* wct */, null /* sct */);
             }
 
             @Override
@@ -332,7 +334,7 @@
                     SurfaceControl.Transaction t,
                     IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
                 remoteCalled[0] = true;
-                finishCallback.onTransitionFinished(remoteFinishWCT);
+                finishCallback.onTransitionFinished(remoteFinishWCT, null /* sct */);
             }
 
             @Override
@@ -358,9 +360,11 @@
         oneShot.setTransition(transitToken);
         IBinder anotherToken = new Binder();
         assertFalse(oneShot.startAnimation(anotherToken, new TransitionInfo(transitType, 0),
-                mock(SurfaceControl.Transaction.class), testFinish));
+                mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class),
+                testFinish));
         assertTrue(oneShot.startAnimation(transitToken, new TransitionInfo(transitType, 0),
-                mock(SurfaceControl.Transaction.class), testFinish));
+                mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class),
+                testFinish));
     }
 
     @Test
@@ -477,7 +481,8 @@
 
         @Override
         public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-                @NonNull SurfaceControl.Transaction t,
+                @NonNull SurfaceControl.Transaction startTransaction,
+                @NonNull SurfaceControl.Transaction finishTransaction,
                 @NonNull Transitions.TransitionFinishCallback finishCallback) {
             mFinishes.add(finishCallback);
             return true;
diff --git a/media/Android.bp b/media/Android.bp
index a66236e..cf4a0b1 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -8,23 +8,6 @@
 }
 
 aidl_interface {
-    name: "audio_common-aidl",
-    unstable: true,
-    host_supported: true,
-    vendor_available: true,
-    local_include_dir: "aidl",
-    double_loadable: true,
-    srcs: [
-        "aidl/android/media/audio/common/AudioChannelMask.aidl",
-        "aidl/android/media/audio/common/AudioConfig.aidl",
-        "aidl/android/media/audio/common/AudioFormat.aidl",
-        "aidl/android/media/audio/common/AudioOffloadInfo.aidl",
-        "aidl/android/media/audio/common/AudioStreamType.aidl",
-        "aidl/android/media/audio/common/AudioUsage.aidl",
-    ],
-}
-
-aidl_interface {
     name: "media_permission-aidl",
     unstable: true,
     host_supported: true,
@@ -40,30 +23,92 @@
     name: "soundtrigger_middleware-aidl",
     unstable: true,
     local_include_dir: "aidl",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+    },
     srcs: [
-        "aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl",
-        "aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl",
         "aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl",
         "aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl",
         "aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl",
-        "aidl/android/media/soundtrigger_middleware/ModelParameter.aidl",
-        "aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl",
-        "aidl/android/media/soundtrigger_middleware/Phrase.aidl",
-        "aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl",
-        "aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl",
-        "aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl",
-        "aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl",
-        "aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl",
-        "aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl",
-        "aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl",
-        "aidl/android/media/soundtrigger_middleware/SoundModel.aidl",
-        "aidl/android/media/soundtrigger_middleware/SoundModelType.aidl",
         "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
-        "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl",
-        "aidl/android/media/soundtrigger_middleware/Status.aidl",
     ],
     imports: [
-        "audio_common-aidl",
+        "android.media.soundtrigger.types",
         "media_permission-aidl",
     ],
 }
+
+aidl_interface {
+    name: "android.media.audio.common.types",
+    vendor_available: true,
+    host_supported: true,
+    double_loadable: true,
+    flags: ["-Werror", "-Weverything", ],
+    local_include_dir: "aidl",
+    srcs: [
+        "aidl/android/media/audio/common/AudioChannelMask.aidl",
+        "aidl/android/media/audio/common/AudioConfig.aidl",
+        "aidl/android/media/audio/common/AudioFormat.aidl",
+        "aidl/android/media/audio/common/AudioOffloadInfo.aidl",
+        "aidl/android/media/audio/common/AudioStreamType.aidl",
+        "aidl/android/media/audio/common/AudioUsage.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
+
+aidl_interface {
+    name: "android.media.soundtrigger.types",
+    vendor_available: true,
+    flags: ["-Werror", "-Weverything", ],
+    local_include_dir: "aidl",
+    srcs: [
+        "aidl/android/media/soundtrigger/AudioCapabilities.aidl",
+        "aidl/android/media/soundtrigger/ConfidenceLevel.aidl",
+        "aidl/android/media/soundtrigger/ModelParameter.aidl",
+        "aidl/android/media/soundtrigger/ModelParameterRange.aidl",
+        "aidl/android/media/soundtrigger/Phrase.aidl",
+        "aidl/android/media/soundtrigger/PhraseRecognitionEvent.aidl",
+        "aidl/android/media/soundtrigger/PhraseRecognitionExtra.aidl",
+        "aidl/android/media/soundtrigger/PhraseSoundModel.aidl",
+        "aidl/android/media/soundtrigger/Properties.aidl",
+        "aidl/android/media/soundtrigger/RecognitionConfig.aidl",
+        "aidl/android/media/soundtrigger/RecognitionEvent.aidl",
+        "aidl/android/media/soundtrigger/RecognitionMode.aidl",
+        "aidl/android/media/soundtrigger/RecognitionStatus.aidl",
+        "aidl/android/media/soundtrigger/SoundModel.aidl",
+        "aidl/android/media/soundtrigger/SoundModelType.aidl",
+        "aidl/android/media/soundtrigger/Status.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+    imports: [
+        "android.media.audio.common.types",
+    ],
+}
diff --git a/media/aidl/android/media/audio/common/AudioChannelMask.aidl b/media/aidl/android/media/audio/common/AudioChannelMask.aidl
index b9b08e6..17be8dd 100644
--- a/media/aidl/android/media/audio/common/AudioChannelMask.aidl
+++ b/media/aidl/android/media/audio/common/AudioChannelMask.aidl
@@ -57,8 +57,11 @@
  * checking the channel mask, the implementer should look for ways to fix it
  * with additional information outside of the mask.
  *
+ * TODO: this should be replaced with strings or other mechanisms that are easy to extend, in line
+ *     with the audio HAL conventions.
  * {@hide}
  */
+@VintfStability
 @Backing(type="int")
 enum AudioChannelMask {
     /**
@@ -113,42 +116,43 @@
      */
     OUT_HAPTIC_A = 0x20000000,
     OUT_HAPTIC_B = 0x10000000,
-// TODO(ytai): Aliases not currently supported in AIDL - can inline the values.
-//    OUT_MONO = OUT_FRONT_LEFT,
-//    OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
-//    OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
-//    OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-//    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY),
-//    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-//    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY),
-//    OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_BACK_LEFT | OUT_BACK_RIGHT),
-//    OUT_QUAD_BACK = OUT_QUAD,
-//    /**
-//     * like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_*
-//     */
-//    OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-//    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_BACK_CENTER),
-//    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
-//    OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT),
-//    OUT_5POINT1_BACK = OUT_5POINT1,
-//    /**
-//     * like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_*
-//     */
-//    OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-//    OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-//    OUT_5POINT1POINT4 = (OUT_5POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
-//    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_BACK_CENTER),
-//    /**
-//     * matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
-//     */
-//    OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-//    OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
-//    OUT_7POINT1POINT4 = (OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
-//    OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
-//    OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
-//    OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
-//    OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
-//    OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A | OUT_HAPTIC_B),
+
+    OUT_MONO = OUT_FRONT_LEFT,
+    OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+    OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
+    OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY),
+    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT | OUT_LOW_FREQUENCY),
+    OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_QUAD_BACK = OUT_QUAD,
+    /**
+     * like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_*
+     */
+    OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_BACK_CENTER),
+    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+    OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_5POINT1_BACK = OUT_5POINT1,
+    /**
+     * like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_*
+     */
+    OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_5POINT1POINT4 = (OUT_5POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_BACK_CENTER),
+    /**
+     * matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
+     */
+    OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | OUT_BACK_LEFT | OUT_BACK_RIGHT | OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_7POINT1POINT4 = (OUT_7POINT1 | OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT | OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+    OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
+    OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
+    OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
+    OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
+    OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A | OUT_HAPTIC_B),
+
     /**
      * These are bits only, not complete values
      *
diff --git a/media/aidl/android/media/audio/common/AudioConfig.aidl b/media/aidl/android/media/audio/common/AudioConfig.aidl
index 50dd796..d128561 100644
--- a/media/aidl/android/media/audio/common/AudioConfig.aidl
+++ b/media/aidl/android/media/audio/common/AudioConfig.aidl
@@ -27,10 +27,12 @@
  *
  * {@hide}
  */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
 parcelable AudioConfig {
     int sampleRateHz;
     int channelMask;
-    AudioFormat format;
+    AudioFormat format = AudioFormat.INVALID;
     AudioOffloadInfo offloadInfo;
     long frameCount;
 }
diff --git a/media/aidl/android/media/audio/common/AudioFormat.aidl b/media/aidl/android/media/audio/common/AudioFormat.aidl
index aadc8e2..73fbca2 100644
--- a/media/aidl/android/media/audio/common/AudioFormat.aidl
+++ b/media/aidl/android/media/audio/common/AudioFormat.aidl
@@ -32,6 +32,7 @@
  *
  * {@hide}
  */
+@VintfStability
 @Backing(type="int")
 enum AudioFormat {
    INVALID = 0xFFFFFFFF,
diff --git a/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
index ec10d71..7be5e6a 100644
--- a/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
+++ b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
@@ -28,17 +28,19 @@
  *
  * {@hide}
  */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
 parcelable AudioOffloadInfo {
     int sampleRateHz;
     int channelMask;
-    AudioFormat format;
-    AudioStreamType streamType;
+    AudioFormat format = AudioFormat.INVALID;
+    AudioStreamType streamType = AudioStreamType.INVALID;
     int bitRatePerSecond;
     long durationMicroseconds;
     boolean hasVideo;
     boolean isStreaming;
     int bitWidth;
     int bufferSize;
-    AudioUsage usage;
+    AudioUsage usage = AudioUsage.INVALID;
 }
 
diff --git a/media/aidl/android/media/audio/common/AudioStreamType.aidl b/media/aidl/android/media/audio/common/AudioStreamType.aidl
index c545667..8b70367 100644
--- a/media/aidl/android/media/audio/common/AudioStreamType.aidl
+++ b/media/aidl/android/media/audio/common/AudioStreamType.aidl
@@ -26,8 +26,14 @@
  *
  * {@hide}
  */
+@VintfStability
 @Backing(type="int")
 enum AudioStreamType {
+    /**
+     * Used as default value in parcelables to indicate that a value was not set.
+     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     */
+    INVALID = -2,
     DEFAULT = -1,
     MIN = 0,
     VOICE_CALL = 0,
diff --git a/media/aidl/android/media/audio/common/AudioUsage.aidl b/media/aidl/android/media/audio/common/AudioUsage.aidl
index ef34816..028eefe 100644
--- a/media/aidl/android/media/audio/common/AudioUsage.aidl
+++ b/media/aidl/android/media/audio/common/AudioUsage.aidl
@@ -22,8 +22,14 @@
 /**
  * {@hide}
  */
+@VintfStability
 @Backing(type="int")
 enum AudioUsage {
+    /**
+     * Used as default value in parcelables to indicate that a value was not set.
+     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     */
+    INVALID = -1,
     UNKNOWN = 0,
     MEDIA = 1,
     VOICE_COMMUNICATION = 2,
diff --git a/media/aidl/android/media/permission/Identity.aidl b/media/aidl/android/media/permission/Identity.aidl
index 3638904..5249786 100644
--- a/media/aidl/android/media/permission/Identity.aidl
+++ b/media/aidl/android/media/permission/Identity.aidl
@@ -20,6 +20,7 @@
  *
  * {@hide}
  */
+@JavaDerive(equals = true, toString = true)
 parcelable Identity {
     /** Linux user ID. */
     int uid = -1;
diff --git a/media/aidl/android/media/soundtrigger/AudioCapabilities.aidl b/media/aidl/android/media/soundtrigger/AudioCapabilities.aidl
new file mode 100644
index 0000000..7b0825b
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/AudioCapabilities.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * AudioCapabilities supported by the implemented HAL driver.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum AudioCapabilities {
+    /**
+     * If set the underlying module supports AEC.
+     */
+    ECHO_CANCELLATION = 1 << 0,
+    /**
+     * If set, the underlying module supports noise suppression.
+     */
+    NOISE_SUPPRESSION = 1 << 1,
+}
diff --git a/media/aidl/android/media/soundtrigger/ConfidenceLevel.aidl b/media/aidl/android/media/soundtrigger/ConfidenceLevel.aidl
new file mode 100644
index 0000000..3fcba40
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/ConfidenceLevel.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * A recognition confidence level.
+ * This type is used to represent either a threshold or an actual detection confidence level.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable ConfidenceLevel {
+    /** user ID. */
+    int userId;
+    /**
+     * Confidence level in percent (0 - 100).
+     * <ul>
+     * <li>Min level for recognition configuration
+     * <li>Detected level for recognition event.
+     * </ul>
+     */
+    int levelPercent;
+}
diff --git a/media/aidl/android/media/soundtrigger/ModelParameter.aidl b/media/aidl/android/media/soundtrigger/ModelParameter.aidl
new file mode 100644
index 0000000..9484008
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/ModelParameter.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * Model specific parameters to be used with parameter set and get APIs.
+ *
+ * {@hide}
+ */
+@VintfStability
+@Backing(type="int")
+enum ModelParameter {
+    /**
+     * Placeholder for invalid model parameter used for returning error or
+     * passing an invalid value.
+     */
+    INVALID = -1,
+
+    /**
+     * Controls the sensitivity threshold adjustment factor for a given model.
+     * Negative value corresponds to less sensitive model (high threshold) and
+     * a positive value corresponds to a more sensitive model (low threshold).
+     * Default value is 0.
+     */
+    THRESHOLD_FACTOR = 0,
+}
diff --git a/media/aidl/android/media/soundtrigger/ModelParameterRange.aidl b/media/aidl/android/media/soundtrigger/ModelParameterRange.aidl
new file mode 100644
index 0000000..e7c616b
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/ModelParameterRange.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * Value range for a model parameter.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable ModelParameterRange {
+    /** Minimum (inclusive) */
+    int minInclusive;
+    /** Maximum (inclusive) */
+    int maxInclusive;
+}
diff --git a/media/aidl/android/media/soundtrigger/Phrase.aidl b/media/aidl/android/media/soundtrigger/Phrase.aidl
new file mode 100644
index 0000000..077db21
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/Phrase.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * Key phrase descriptor.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable Phrase {
+    /** Unique keyphrase ID assigned at enrollment time. */
+    int id;
+    /** Recognition modes supported by this key phrase (bitfield of RecognitionMode enum). */
+    int recognitionModes;
+    /** List of users IDs associated with this key phrase. */
+    int[] users;
+    /** Locale - Java Locale style (e.g. en_US). */
+    String locale;
+    /** Phrase text. */
+    String text;
+}
diff --git a/media/aidl/android/media/soundtrigger/PhraseRecognitionEvent.aidl b/media/aidl/android/media/soundtrigger/PhraseRecognitionEvent.aidl
new file mode 100644
index 0000000..654f7c2
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/PhraseRecognitionEvent.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.RecognitionEvent;
+
+/**
+ * An event that gets sent to indicate a phrase recognition (or aborting of the recognition
+   process).
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable PhraseRecognitionEvent {
+    /** Common recognition event. */
+    RecognitionEvent common;
+    /** List of descriptors for each recognized key phrase */
+    PhraseRecognitionExtra[] phraseExtras;
+}
diff --git a/media/aidl/android/media/soundtrigger/PhraseRecognitionExtra.aidl b/media/aidl/android/media/soundtrigger/PhraseRecognitionExtra.aidl
new file mode 100644
index 0000000..eb523eb
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/PhraseRecognitionExtra.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+import android.media.soundtrigger.ConfidenceLevel;
+
+/**
+ * Specialized recognition event for key phrase detection.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable PhraseRecognitionExtra {
+    /** Keyphrase ID */
+    int id;
+    /** Bitfield, indexed by RecognitionMode. */
+    int recognitionModes;
+    /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER. Value is between 0-100. */
+    int confidenceLevel;
+    /** Number of user confidence levels */
+    ConfidenceLevel[] levels;
+}
diff --git a/media/aidl/android/media/soundtrigger/PhraseSoundModel.aidl b/media/aidl/android/media/soundtrigger/PhraseSoundModel.aidl
new file mode 100644
index 0000000..e0ffdee
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/PhraseSoundModel.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Phrase;
+
+/**
+ * Specialized sound model for key phrase detection.
+ * Proprietary representation of key phrases in binary data must match
+ * information indicated by phrases field.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable PhraseSoundModel {
+    /** Common part of sound model descriptor */
+    SoundModel common;
+    /** List of descriptors for key phrases supported by this sound model */
+    Phrase[] phrases;
+}
diff --git a/media/aidl/android/media/soundtrigger/Properties.aidl b/media/aidl/android/media/soundtrigger/Properties.aidl
new file mode 100644
index 0000000..efa1b6a
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/Properties.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * Capabilities of a sound trigger module.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable Properties {
+    /** Implementor name */
+    String   implementor;
+    /** Implementation description */
+    String   description;
+    /** Implementation version */
+    int version;
+    /**
+     * Unique implementation ID. The UUID must change with each version of
+       the engine implementation */
+    String     uuid;
+    /**
+     * String naming the architecture used for running the supported models.
+     * (eg. a platform running models on a DSP could implement this string to convey the DSP
+     * architecture used)
+     * This property is supported for soundtrigger HAL v2.3 and above.
+     * If running a previous version, the string will be empty.
+     */
+    String supportedModelArch;
+    /** Maximum number of concurrent sound models loaded */
+    int maxSoundModels;
+    /** Maximum number of key phrases */
+    int maxKeyPhrases;
+    /** Maximum number of concurrent users detected */
+    int maxUsers;
+    /** All supported modes. Bitfield, indexed by RecognitionMode. */
+    int recognitionModes;
+    /** Supports seamless transition from detection to capture */
+    boolean     captureTransition;
+    /** Maximum buffering capacity in ms if captureTransition is true */
+    int maxBufferMs;
+    /** Supports capture by other use cases while detection is active */
+    boolean     concurrentCapture;
+    /** Returns the trigger capture in event */
+    boolean     triggerInEvent;
+    /**
+     * Rated power consumption when detection is active with TDB
+     * silence/sound/speech ratio */
+    int powerConsumptionMw;
+    /**
+     * Bit field encoding of the AudioCapabilities
+     * supported by the firmware.
+     * This property is supported for soundtrigger HAL v2.3 and above.
+     * If running a previous version, this value will be 0.
+     */
+    int audioCapabilities;
+}
diff --git a/media/aidl/android/media/soundtrigger/RecognitionConfig.aidl b/media/aidl/android/media/soundtrigger/RecognitionConfig.aidl
new file mode 100644
index 0000000..a00f0e5
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/RecognitionConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+import android.media.soundtrigger.PhraseRecognitionExtra;
+
+/**
+ * Configuration for tuning behavior of an active recognition process.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable RecognitionConfig {
+    /* Capture and buffer audio for this recognition instance. */
+    boolean captureRequested;
+
+    /* Configuration for each key phrase. */
+    PhraseRecognitionExtra[] phraseRecognitionExtras;
+
+    /**
+     * Bit field encoding of the AudioCapabilities
+     * supported by the firmware.
+     */
+    int audioCapabilities;
+
+    /** Capture configuration data. Content is implementation-defined. */
+    byte[] data;
+}
diff --git a/media/aidl/android/media/soundtrigger/RecognitionEvent.aidl b/media/aidl/android/media/soundtrigger/RecognitionEvent.aidl
new file mode 100644
index 0000000..94668a3
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/RecognitionEvent.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+import android.media.audio.common.AudioConfig;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModelType;
+
+/**
+ * An event that gets sent to indicate a recognition (or aborting of the recognition process).
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable RecognitionEvent {
+    /** Recognition status. */
+    RecognitionStatus status = RecognitionStatus.INVALID;
+    /** Event type, same as sound model type. */
+    SoundModelType type = SoundModelType.INVALID;
+    /** Is it possible to capture audio from this utterance buffered by the implementation. */
+    boolean captureAvailable;
+    /**
+     * Delay in ms between end of model detection and start of audio available for capture.
+     * A negative value is possible (e.g. if key phrase is also available for Capture.
+     */
+    int captureDelayMs;
+    /** Duration in ms of audio captured before the start of the trigger. 0 if none. */
+    int capturePreambleMs;
+    /** If true, the 'data' field below contains the capture of the trigger sound. */
+    boolean triggerInData;
+    /**
+     * Audio format of either the trigger in event data or to use for capture of the rest of the
+     * utterance. May be null when no audio is available for this event type.
+     */
+    @nullable AudioConfig audioConfig;
+    /** Additional data. */
+    byte[] data;
+}
diff --git a/media/aidl/android/media/soundtrigger/RecognitionMode.aidl b/media/aidl/android/media/soundtrigger/RecognitionMode.aidl
new file mode 100644
index 0000000..ce2cffe
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/RecognitionMode.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * Recognition mode.
+ * {@hide}
+ */
+@VintfStability
+@Backing(type="int")
+enum RecognitionMode {
+    /** Simple voice trigger. */
+    VOICE_TRIGGER       = 0x1,
+    /** Trigger only if one user in model identified. */
+    USER_IDENTIFICATION = 0x2,
+    /** Trigger only if one user in model authenticated. */
+    USER_AUTHENTICATION = 0x4,
+    /** Generic sound trigger. */
+    GENERIC_TRIGGER     = 0x8,
+}
diff --git a/media/aidl/android/media/soundtrigger/RecognitionStatus.aidl b/media/aidl/android/media/soundtrigger/RecognitionStatus.aidl
new file mode 100644
index 0000000..cccf0f3
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/RecognitionStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * A status for indicating the type of a recognition event.
+ * {@hide}
+ */
+@VintfStability
+@Backing(type="int")
+enum RecognitionStatus {
+    /**
+     * Used as default value in parcelables to indicate that a value was not set.
+     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     */
+    INVALID = -1,
+    /** Recognition success. */
+    SUCCESS = 0,
+    /** Recognition aborted (e.g. capture preempted by another use-case. */
+    ABORTED = 1,
+    /** Recognition failure. */
+    FAILURE = 2,
+    /**
+    * Recognition event was triggered by a forceRecognitionEvent request, not by the DSP.
+    * Note that forced detections *do not* stop the active recognition, unlike the other types.
+    */
+    FORCED = 3
+}
diff --git a/media/aidl/android/media/soundtrigger/SoundModel.aidl b/media/aidl/android/media/soundtrigger/SoundModel.aidl
new file mode 100644
index 0000000..94244d0
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/SoundModel.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+import android.media.soundtrigger.SoundModelType;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Base sound model descriptor. This struct can be extended for various specific types by way of
+ * aggregation.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+@VintfStability
+parcelable SoundModel {
+    /** Model type. */
+    SoundModelType type = SoundModelType.INVALID;
+    /** Unique sound model ID. */
+    String uuid;
+    /**
+     * Unique vendor ID. Identifies the engine the sound model
+     * was build for */
+    String vendorUuid;
+    /** Opaque data transparent to Android framework. May be null if dataSize is 0. */
+    @nullable ParcelFileDescriptor data;
+    /** Size of the above data, in bytes. */
+    int dataSize;
+}
diff --git a/media/aidl/android/media/soundtrigger/SoundModelType.aidl b/media/aidl/android/media/soundtrigger/SoundModelType.aidl
new file mode 100644
index 0000000..34a9376
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/SoundModelType.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * Sound model type.
+ * {@hide}
+ */
+@VintfStability
+@Backing(type="int")
+enum SoundModelType {
+    /**
+     * Used as default value in parcelables to indicate that a value was not set.
+     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     */
+    INVALID = -1,
+    /** Key phrase sound models */
+    KEYPHRASE = 0,
+    /** All models other than keyphrase */
+    GENERIC = 1,
+}
diff --git a/media/aidl/android/media/soundtrigger/Status.aidl b/media/aidl/android/media/soundtrigger/Status.aidl
new file mode 100644
index 0000000..ca1487f
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger/Status.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.soundtrigger;
+
+/**
+ * {@hide}
+ */
+@VintfStability
+@Backing(type="int")
+enum Status {
+    /**
+     * Used as default value in parcelables to indicate that a value was not set.
+     * Should never be considered a valid setting, except for backward compatibility scenarios.
+     */
+    INVALID = -1,
+    /** Success. */
+    SUCCESS = 0,
+    /** Failure due to resource contention. This is typically a temporary condition. */
+    RESOURCE_CONTENTION = 1,
+    /** Operation is not supported in this implementation. This is a permanent condition. */
+    OPERATION_NOT_SUPPORTED = 2,
+    /** Temporary lack of permission. */
+    TEMPORARY_PERMISSION_DENIED = 3,
+    /** The object on which this method is called is dead and all of its state is lost. */
+    DEAD_OBJECT = 4,
+    /**
+     * Unexpected internal error has occurred. Usually this will result in the service rebooting
+     * shortly after. The client should treat the state of the server as undefined.
+     */
+    INTERNAL_ERROR = 5,
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl b/media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl
deleted file mode 100644
index 97a8849..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * AudioCapabilities supported by the implemented HAL driver.
- * @hide
- */
-@Backing(type="int")
-enum AudioCapabilities {
-    /**
-     * If set the underlying module supports AEC.
-     */
-    ECHO_CANCELLATION = 1 << 0,
-    /**
-     * If set, the underlying module supports noise suppression.
-     */
-    NOISE_SUPPRESSION = 1 << 1,
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl b/media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
deleted file mode 100644
index 3dbc705..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * A recognition confidence level.
- * This type is used to represent either a threshold or an actual detection confidence level.
- *
- * {@hide}
- */
-parcelable ConfidenceLevel {
-    /** user ID. */
-    int userId;
-    /**
-     * Confidence level in percent (0 - 100).
-     * <ul>
-     * <li>Min level for recognition configuration
-     * <li>Detected level for recognition event.
-     * </ul>
-     */
-    int levelPercent;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
index 726af76..6092ac5 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
@@ -15,8 +15,8 @@
  */
 package android.media.soundtrigger_middleware;
 
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionEvent;
 
 /**
  * Main interface for a client to get notifications of events coming from this module.
@@ -28,22 +28,29 @@
      * Invoked whenever a recognition event is triggered (typically, on recognition, but also in
      * case of external aborting of a recognition or a forced recognition event - see the status
      * code in the event for determining).
+     * In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
+     * callback.
      */
-    void onRecognition(int modelHandle, in RecognitionEvent event);
+    void onRecognition(int modelHandle, in RecognitionEvent event, int captureSession);
      /**
       * Invoked whenever a phrase recognition event is triggered (typically, on recognition, but
       * also in case of external aborting of a recognition or a forced recognition event - see the
       * status code in the event for determining).
+      * In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
+      * callback.
       */
-    void onPhraseRecognition(int modelHandle, in PhraseRecognitionEvent event);
+    void onPhraseRecognition(int modelHandle, in PhraseRecognitionEvent event, int captureSession);
     /**
-     * Notifies the client the recognition has become available after previously having been
-     * unavailable, or vice versa. This method will always be invoked once immediately after
-     * attachment, and then every time there is a change in availability.
-     * When availability changes from available to unavailable, all active recognitions are aborted,
-     * and this event will be sent in addition to the abort event.
+     * Notifies the client that some start/load operations that have previously failed for resource
+     * reasons (threw a ServiceSpecificException(RESOURCE_CONTENTION) or have been preempted) may
+     * now succeed. This is not a guarantee, but a hint for the client to retry.
      */
-    void onRecognitionAvailabilityChange(boolean available);
+    void onResourcesAvailable();
+    /**
+     * Notifies the client that a model had been preemptively unloaded by the service.
+     * The caller may retry after the next onRecognitionAvailabilityChange() callback.
+     */
+    void onModelUnloaded(int modelHandle);
     /**
      * Notifies the client that the associated module has crashed and restarted. The module instance
      * is no longer usable and will throw a ServiceSpecificException with a Status.DEAD_OBJECT code
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
index c4a5785..0b46fd4 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
@@ -15,11 +15,11 @@
  */
 package android.media.soundtrigger_middleware;
 
-import android.media.soundtrigger_middleware.ModelParameter;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.SoundModel;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
+import android.media.soundtrigger.ModelParameter;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.RecognitionConfig;
 
 /**
  * A sound-trigger module.
@@ -75,6 +75,9 @@
      * Once a recognition event is passed to the client, the recognition automatically become
      * inactive, unless the event is of the RecognitionStatus.FORCED kind. Client can also shut down
      * the recognition explicitly, via stopRecognition.
+     *
+     * May throw a ServiceSpecificException with an RESOURCE_CONTENTION status to indicate that
+     * resources required for starting the model are currently consumed by other clients.
      */
     void startRecognition(int modelHandle, in RecognitionConfig config);
 
diff --git a/media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl b/media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl
deleted file mode 100644
index 0993627..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * Model specific parameters to be used with parameter set and get APIs.
- *
- * {@hide}
- */
-@Backing(type="int")
-enum ModelParameter {
-    /**
-     * Placeholder for invalid model parameter used for returning error or
-     * passing an invalid value.
-     */
-    INVALID = -1,
-
-    /**
-     * Controls the sensitivity threshold adjustment factor for a given model.
-     * Negative value corresponds to less sensitive model (high threshold) and
-     * a positive value corresponds to a more sensitive model (low threshold).
-     * Default value is 0.
-     */
-    THRESHOLD_FACTOR = 0,
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl b/media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl
deleted file mode 100644
index d6948a8..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * Value range for a model parameter.
- *
- * {@hide}
- */
-parcelable ModelParameterRange {
-    /** Minimum (inclusive) */
-    int minInclusive;
-    /** Maximum (inclusive) */
-    int maxInclusive;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/Phrase.aidl b/media/aidl/android/media/soundtrigger_middleware/Phrase.aidl
deleted file mode 100644
index 98a489f8..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/Phrase.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * Key phrase descriptor.
- *
- * {@hide}
- */
-parcelable Phrase {
-    /** Unique keyphrase ID assigned at enrollment time. */
-    int id;
-    /** Recognition modes supported by this key phrase (bitfield of RecognitionMode enum). */
-    int recognitionModes;
-    /** List of users IDs associated with this key phrase. */
-    int[] users;
-    /** Locale - Java Locale style (e.g. en_US). */
-    String locale;
-    /** Phrase text. */
-    String text;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
deleted file mode 100644
index 6a3ec61..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-
-/**
- * An event that gets sent to indicate a phrase recognition (or aborting of the recognition
-   process).
- * {@hide}
- */
-parcelable PhraseRecognitionEvent {
-    /** Common recognition event. */
-    RecognitionEvent common;
-    /** List of descriptors for each recognized key phrase */
-    PhraseRecognitionExtra[] phraseExtras;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
deleted file mode 100644
index cb96bf3..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-import android.media.soundtrigger_middleware.ConfidenceLevel;
-
-/**
- * Specialized recognition event for key phrase detection.
- * {@hide}
- */
-parcelable PhraseRecognitionExtra {
-    // TODO(ytai): Constants / enums.
-
-    /** keyphrase ID */
-    int id;
-    /** recognition modes used for this keyphrase */
-    int recognitionModes;
-    /** confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER */
-    int confidenceLevel;
-    /** number of user confidence levels */
-    ConfidenceLevel[] levels;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
deleted file mode 100644
index 81028c1..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-import android.media.soundtrigger_middleware.SoundModel;
-import android.media.soundtrigger_middleware.Phrase;
-
-/**
- * Specialized sound model for key phrase detection.
- * Proprietary representation of key phrases in binary data must match
- * information indicated by phrases field.
- * {@hide}
- */
-parcelable PhraseSoundModel {
-    /** Common part of sound model descriptor */
-    SoundModel common;
-    /** List of descriptors for key phrases supported by this sound model */
-    Phrase[] phrases;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl
deleted file mode 100644
index 5c0eeb1..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-
-/**
- * Configuration for tuning behavior of an active recognition process.
- * {@hide}
- */
-parcelable RecognitionConfig {
-    /* Capture and buffer audio for this recognition instance. */
-    boolean captureRequested;
-
-    /* Configuration for each key phrase. */
-    PhraseRecognitionExtra[] phraseRecognitionExtras;
-
-    /**
-     * Bit field encoding of the AudioCapabilities
-     * supported by the firmware.
-     */
-    int audioCapabilities;
-
-    /** Opaque capture configuration data. */
-    byte[] data;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl
deleted file mode 100644
index a237ec1..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-import android.media.audio.common.AudioConfig;
-import android.media.soundtrigger_middleware.RecognitionStatus;
-import android.media.soundtrigger_middleware.SoundModelType;
-
-/**
- * An event that gets sent to indicate a recognition (or aborting of the recognition process).
- * {@hide}
- */
-parcelable RecognitionEvent {
-    /** Recognition status. */
-    RecognitionStatus status;
-    /** Event type, same as sound model type. */
-    SoundModelType type;
-    /** Is it possible to capture audio from this utterance buffered by the implementation. */
-    boolean captureAvailable;
-    /* Audio session ID. framework use. */
-    int captureSession;
-    /**
-     * Delay in ms between end of model detection and start of audio available for capture.
-     * A negative value is possible (e.g. if key phrase is also available for Capture.
-     */
-    int captureDelayMs;
-    /** Duration in ms of audio captured before the start of the trigger. 0 if none. */
-    int capturePreambleMs;
-    /** If true, the 'data' field below contains the capture of the trigger sound. */
-    boolean triggerInData;
-    /**
-     * Audio format of either the trigger in event data or to use for capture of the rest of the
-     * utterance. May be null when no audio is available for this event type.
-     */
-    @nullable AudioConfig audioConfig;
-    /** Additional data. */
-    byte[] data;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl
deleted file mode 100644
index d8bfff4..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * Recognition mode.
- * {@hide}
- */
-@Backing(type="int")
-enum RecognitionMode {
-    /** Simple voice trigger. */
-    VOICE_TRIGGER       = 0x1,
-    /** Trigger only if one user in model identified. */
-    USER_IDENTIFICATION = 0x2,
-    /** Trigger only if one user in model authenticated. */
-    USER_AUTHENTICATION = 0x4,
-    /** Generic sound trigger. */
-    GENERIC_TRIGGER     = 0x8,
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl
deleted file mode 100644
index d563edc..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * A status for indicating the type of a recognition event.
- * {@hide}
- */
-@Backing(type="int")
-enum RecognitionStatus {
-    /** Recognition success. */
-    SUCCESS = 0,
-    /** Recognition aborted (e.g. capture preempted by another use-case. */
-    ABORTED = 1,
-    /** Recognition failure. */
-    FAILURE = 2,
-    /**
-    * Recognition event was triggered by a forceRecognitionEvent request, not by the DSP.
-    * Note that forced detections *do not* stop the active recognition, unlike the other types.
-    */
-    FORCED = 3
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
deleted file mode 100644
index 8186fb7..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-import android.media.soundtrigger_middleware.SoundModelType;
-import android.os.ParcelFileDescriptor;
-
-/**
- * Base sound model descriptor. This struct can be extended for various specific types by way of
- * aggregation.
- * {@hide}
- */
-parcelable SoundModel {
-    /** Model type. */
-    SoundModelType type;
-    /** Unique sound model ID. */
-    String uuid;
-    /**
-     * Unique vendor ID. Identifies the engine the sound model
-     * was build for */
-    String vendorUuid;
-    /** Opaque data transparent to Android framework. May be null if dataSize is 0. */
-    @nullable ParcelFileDescriptor data;
-    /** Size of the above data, in bytes. */
-    int dataSize;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl
deleted file mode 100644
index f2abc9a..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * Sound model type.
- * {@hide}
- */
-@Backing(type="int")
-enum SoundModelType {
-    /** Unspecified sound model type */
-    UNKNOWN = -1,
-    /** Key phrase sound models */
-    KEYPHRASE = 0,
-    /** All models other than keyphrase */
-    GENERIC = 1,
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
index 667135f..6c210bf 100644
--- a/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
@@ -15,17 +15,18 @@
  */
 package android.media.soundtrigger_middleware;
 
-import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
+import android.media.soundtrigger.Properties;
 
 /**
  * A descriptor of an available sound trigger module, containing the handle used to reference the
  * module, as well its capabilities.
  * {@hide}
  */
+@JavaDerive(equals = true, toString = true)
 parcelable SoundTriggerModuleDescriptor {
     /** Module handle to be used for attaching to it. */
     int handle;
     /** Module capabilities. */
-    SoundTriggerModuleProperties properties;
+    Properties properties;
 }
 
diff --git a/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
deleted file mode 100644
index 9c56e7b..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * Capabilities of a sound trigger module.
- * {@hide}
- */
-parcelable SoundTriggerModuleProperties {
-    /** Implementor name */
-    String   implementor;
-    /** Implementation description */
-    String   description;
-    /** Implementation version */
-    int version;
-    /**
-     * Unique implementation ID. The UUID must change with each version of
-       the engine implementation */
-    String     uuid;
-    /**
-     * String naming the architecture used for running the supported models.
-     * (eg. a platform running models on a DSP could implement this string to convey the DSP
-     * architecture used)
-     * This property is supported for soundtrigger HAL v2.3 and above.
-     * If running a previous version, the string will be empty.
-     */
-    String supportedModelArch;
-    /** Maximum number of concurrent sound models loaded */
-    int maxSoundModels;
-    /** Maximum number of key phrases */
-    int maxKeyPhrases;
-    /** Maximum number of concurrent users detected */
-    int maxUsers;
-    /** All supported modes. e.g RecognitionMode.VOICE_TRIGGER */
-    int recognitionModes;
-    /** Supports seamless transition from detection to capture */
-    boolean     captureTransition;
-    /** Maximum buffering capacity in ms if captureTransition is true */
-    int maxBufferMs;
-    /** Supports capture by other use cases while detection is active */
-    boolean     concurrentCapture;
-    /** Returns the trigger capture in event */
-    boolean     triggerInEvent;
-    /**
-     * Rated power consumption when detection is active with TDB
-     * silence/sound/speech ratio */
-    int powerConsumptionMw;
-    /**
-     * Bit field encoding of the AudioCapabilities
-     * supported by the firmware.
-     * This property is supported for soundtrigger HAL v2.3 and above.
-     * If running a previous version, this value will be 0.
-     */
-    int audioCapabilities;
-}
diff --git a/media/aidl/android/media/soundtrigger_middleware/Status.aidl b/media/aidl/android/media/soundtrigger_middleware/Status.aidl
deleted file mode 100644
index c7623f5..0000000
--- a/media/aidl/android/media/soundtrigger_middleware/Status.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.soundtrigger_middleware;
-
-/**
- * {@hide}
- */
-@Backing(type="int")
-enum Status {
-    /** Success. */
-    SUCCESS = 0,
-    /** Failure due to resource contention. This is typically a temporary condition. */
-    RESOURCE_CONTENTION = 1,
-    /** Operation is not supported in this implementation. This is a permanent condition. */
-    OPERATION_NOT_SUPPORTED = 2,
-    /** Temporary lack of permission. */
-    TEMPORARY_PERMISSION_DENIED = 3,
-    /** The object on which this method is called is dead and all of its state is lost. */
-    DEAD_OBJECT = 4,
-    /**
-     * Unexpected internal error has occurred. Usually this will result in the service rebooting
-     * shortly after. The client should treat the state of the server as undefined.
-     */
-    INTERNAL_ERROR = 5,
-}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelMask.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelMask.aidl
new file mode 100644
index 0000000..c3af3bf
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioChannelMask.aidl
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
+// hardware/interfaces/audio/common/5.0/types.hal
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum AudioChannelMask {
+  REPRESENTATION_POSITION = 0,
+  REPRESENTATION_INDEX = 2,
+  NONE = 0,
+  INVALID = -1073741824,
+  OUT_FRONT_LEFT = 1,
+  OUT_FRONT_RIGHT = 2,
+  OUT_FRONT_CENTER = 4,
+  OUT_LOW_FREQUENCY = 8,
+  OUT_BACK_LEFT = 16,
+  OUT_BACK_RIGHT = 32,
+  OUT_FRONT_LEFT_OF_CENTER = 64,
+  OUT_FRONT_RIGHT_OF_CENTER = 128,
+  OUT_BACK_CENTER = 256,
+  OUT_SIDE_LEFT = 512,
+  OUT_SIDE_RIGHT = 1024,
+  OUT_TOP_CENTER = 2048,
+  OUT_TOP_FRONT_LEFT = 4096,
+  OUT_TOP_FRONT_CENTER = 8192,
+  OUT_TOP_FRONT_RIGHT = 16384,
+  OUT_TOP_BACK_LEFT = 32768,
+  OUT_TOP_BACK_CENTER = 65536,
+  OUT_TOP_BACK_RIGHT = 131072,
+  OUT_TOP_SIDE_LEFT = 262144,
+  OUT_TOP_SIDE_RIGHT = 524288,
+  OUT_HAPTIC_A = 536870912,
+  OUT_HAPTIC_B = 268435456,
+  OUT_MONO = 1,
+  OUT_STEREO = 3,
+  OUT_2POINT1 = 11,
+  OUT_2POINT0POINT2 = 786435,
+  OUT_2POINT1POINT2 = 786443,
+  OUT_3POINT0POINT2 = 786439,
+  OUT_3POINT1POINT2 = 786447,
+  OUT_QUAD = 51,
+  OUT_QUAD_BACK = 51,
+  OUT_QUAD_SIDE = 1539,
+  OUT_SURROUND = 263,
+  OUT_PENTA = 55,
+  OUT_5POINT1 = 63,
+  OUT_5POINT1_BACK = 63,
+  OUT_5POINT1_SIDE = 1551,
+  OUT_5POINT1POINT2 = 786495,
+  OUT_5POINT1POINT4 = 184383,
+  OUT_6POINT1 = 319,
+  OUT_7POINT1 = 1599,
+  OUT_7POINT1POINT2 = 788031,
+  OUT_7POINT1POINT4 = 185919,
+  OUT_MONO_HAPTIC_A = 536870913,
+  OUT_STEREO_HAPTIC_A = 536870915,
+  OUT_HAPTIC_AB = 805306368,
+  OUT_MONO_HAPTIC_AB = 805306369,
+  OUT_STEREO_HAPTIC_AB = 805306371,
+  IN_LEFT = 4,
+  IN_RIGHT = 8,
+  IN_FRONT = 16,
+  IN_BACK = 32,
+  IN_LEFT_PROCESSED = 64,
+  IN_RIGHT_PROCESSED = 128,
+  IN_FRONT_PROCESSED = 256,
+  IN_BACK_PROCESSED = 512,
+  IN_PRESSURE = 1024,
+  IN_X_AXIS = 2048,
+  IN_Y_AXIS = 4096,
+  IN_Z_AXIS = 8192,
+  IN_BACK_LEFT = 65536,
+  IN_BACK_RIGHT = 131072,
+  IN_CENTER = 262144,
+  IN_LOW_FREQUENCY = 1048576,
+  IN_TOP_LEFT = 2097152,
+  IN_TOP_RIGHT = 4194304,
+  IN_VOICE_UPLINK = 16384,
+  IN_VOICE_DNLINK = 32768,
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl
new file mode 100644
index 0000000..c11eb76
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioConfig.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
+// hardware/interfaces/audio/common/5.0/types.hal
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioConfig {
+  int sampleRateHz;
+  int channelMask;
+  android.media.audio.common.AudioFormat format = android.media.audio.common.AudioFormat.INVALID;
+  android.media.audio.common.AudioOffloadInfo offloadInfo;
+  long frameCount;
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormat.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormat.aidl
new file mode 100644
index 0000000..b7c8659
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioFormat.aidl
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
+// hardware/interfaces/audio/common/5.0/types.hal
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum AudioFormat {
+  INVALID = -1,
+  DEFAULT = 0,
+  PCM = 0,
+  MP3 = 16777216,
+  AMR_NB = 33554432,
+  AMR_WB = 50331648,
+  AAC = 67108864,
+  HE_AAC_V1 = 83886080,
+  HE_AAC_V2 = 100663296,
+  VORBIS = 117440512,
+  OPUS = 134217728,
+  AC3 = 150994944,
+  E_AC3 = 167772160,
+  DTS = 184549376,
+  DTS_HD = 201326592,
+  IEC61937 = 218103808,
+  DOLBY_TRUEHD = 234881024,
+  EVRC = 268435456,
+  EVRCB = 285212672,
+  EVRCWB = 301989888,
+  EVRCNW = 318767104,
+  AAC_ADIF = 335544320,
+  WMA = 352321536,
+  WMA_PRO = 369098752,
+  AMR_WB_PLUS = 385875968,
+  MP2 = 402653184,
+  QCELP = 419430400,
+  DSD = 436207616,
+  FLAC = 452984832,
+  ALAC = 469762048,
+  APE = 486539264,
+  AAC_ADTS = 503316480,
+  SBC = 520093696,
+  APTX = 536870912,
+  APTX_HD = 553648128,
+  AC4 = 570425344,
+  LDAC = 587202560,
+  MAT = 603979776,
+  AAC_LATM = 620756992,
+  CELT = 637534208,
+  APTX_ADAPTIVE = 654311424,
+  LHDC = 671088640,
+  LHDC_LL = 687865856,
+  APTX_TWSP = 704643072,
+  MAIN_MASK = -16777216,
+  SUB_MASK = 16777215,
+  PCM_SUB_16_BIT = 1,
+  PCM_SUB_8_BIT = 2,
+  PCM_SUB_32_BIT = 3,
+  PCM_SUB_8_24_BIT = 4,
+  PCM_SUB_FLOAT = 5,
+  PCM_SUB_24_BIT_PACKED = 6,
+  MP3_SUB_NONE = 0,
+  AMR_SUB_NONE = 0,
+  AAC_SUB_MAIN = 1,
+  AAC_SUB_LC = 2,
+  AAC_SUB_SSR = 4,
+  AAC_SUB_LTP = 8,
+  AAC_SUB_HE_V1 = 16,
+  AAC_SUB_SCALABLE = 32,
+  AAC_SUB_ERLC = 64,
+  AAC_SUB_LD = 128,
+  AAC_SUB_HE_V2 = 256,
+  AAC_SUB_ELD = 512,
+  AAC_SUB_XHE = 768,
+  VORBIS_SUB_NONE = 0,
+  E_AC3_SUB_JOC = 1,
+  MAT_SUB_1_0 = 1,
+  MAT_SUB_2_0 = 2,
+  MAT_SUB_2_1 = 3,
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl
new file mode 100644
index 0000000..b5d889e
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioOffloadInfo.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
+// hardware/interfaces/audio/common/5.0/types.hal
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioOffloadInfo {
+  int sampleRateHz;
+  int channelMask;
+  android.media.audio.common.AudioFormat format = android.media.audio.common.AudioFormat.INVALID;
+  android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
+  int bitRatePerSecond;
+  long durationMicroseconds;
+  boolean hasVideo;
+  boolean isStreaming;
+  int bitWidth;
+  int bufferSize;
+  android.media.audio.common.AudioUsage usage = android.media.audio.common.AudioUsage.INVALID;
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl
new file mode 100644
index 0000000..915c668
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioStreamType.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
+// hardware/interfaces/audio/common/5.0/types.hal
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum AudioStreamType {
+  INVALID = -2,
+  DEFAULT = -1,
+  MIN = 0,
+  VOICE_CALL = 0,
+  SYSTEM = 1,
+  RING = 2,
+  MUSIC = 3,
+  ALARM = 4,
+  NOTIFICATION = 5,
+  BLUETOOTH_SCO = 6,
+  ENFORCED_AUDIBLE = 7,
+  DTMF = 8,
+  TTS = 9,
+  ACCESSIBILITY = 10,
+}
diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl
new file mode 100644
index 0000000..f5130a4
--- /dev/null
+++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/AudioUsage.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */// This file has been semi-automatically generated using hidl2aidl from its counterpart in
+// hardware/interfaces/audio/common/5.0/types.hal
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio.common;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum AudioUsage {
+  INVALID = -1,
+  UNKNOWN = 0,
+  MEDIA = 1,
+  VOICE_COMMUNICATION = 2,
+  VOICE_COMMUNICATION_SIGNALLING = 3,
+  ALARM = 4,
+  NOTIFICATION = 5,
+  NOTIFICATION_TELEPHONY_RINGTONE = 6,
+  ASSISTANCE_ACCESSIBILITY = 11,
+  ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+  ASSISTANCE_SONIFICATION = 13,
+  GAME = 14,
+  VIRTUAL_SOURCE = 15,
+  ASSISTANT = 16,
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/AudioCapabilities.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/AudioCapabilities.aidl
new file mode 100644
index 0000000..5d88305
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/AudioCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum AudioCapabilities {
+  ECHO_CANCELLATION = 1,
+  NOISE_SUPPRESSION = 2,
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ConfidenceLevel.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ConfidenceLevel.aidl
new file mode 100644
index 0000000..5127a11
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ConfidenceLevel.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ConfidenceLevel {
+  int userId;
+  int levelPercent;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ModelParameter.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ModelParameter.aidl
new file mode 100644
index 0000000..aadbf80
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ModelParameter.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum ModelParameter {
+  INVALID = -1,
+  THRESHOLD_FACTOR = 0,
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ModelParameterRange.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ModelParameterRange.aidl
new file mode 100644
index 0000000..f29b728
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/ModelParameterRange.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ModelParameterRange {
+  int minInclusive;
+  int maxInclusive;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Phrase.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Phrase.aidl
new file mode 100644
index 0000000..11029ba
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Phrase.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Phrase {
+  int id;
+  int recognitionModes;
+  int[] users;
+  String locale;
+  String text;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseRecognitionEvent.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseRecognitionEvent.aidl
new file mode 100644
index 0000000..b75d1b8
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseRecognitionEvent.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable PhraseRecognitionEvent {
+  android.media.soundtrigger.RecognitionEvent common;
+  android.media.soundtrigger.PhraseRecognitionExtra[] phraseExtras;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseRecognitionExtra.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseRecognitionExtra.aidl
new file mode 100644
index 0000000..e417c69
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseRecognitionExtra.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable PhraseRecognitionExtra {
+  int id;
+  int recognitionModes;
+  int confidenceLevel;
+  android.media.soundtrigger.ConfidenceLevel[] levels;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseSoundModel.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseSoundModel.aidl
new file mode 100644
index 0000000..b4b3854
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/PhraseSoundModel.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable PhraseSoundModel {
+  android.media.soundtrigger.SoundModel common;
+  android.media.soundtrigger.Phrase[] phrases;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Properties.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Properties.aidl
new file mode 100644
index 0000000..068db52
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Properties.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Properties {
+  String implementor;
+  String description;
+  int version;
+  String uuid;
+  String supportedModelArch;
+  int maxSoundModels;
+  int maxKeyPhrases;
+  int maxUsers;
+  int recognitionModes;
+  boolean captureTransition;
+  int maxBufferMs;
+  boolean concurrentCapture;
+  boolean triggerInEvent;
+  int powerConsumptionMw;
+  int audioCapabilities;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionConfig.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionConfig.aidl
new file mode 100644
index 0000000..63cd2cbb
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionConfig.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable RecognitionConfig {
+  boolean captureRequested;
+  android.media.soundtrigger.PhraseRecognitionExtra[] phraseRecognitionExtras;
+  int audioCapabilities;
+  byte[] data;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionEvent.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionEvent.aidl
new file mode 100644
index 0000000..e6cfb6b
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionEvent.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable RecognitionEvent {
+  android.media.soundtrigger.RecognitionStatus status = android.media.soundtrigger.RecognitionStatus.INVALID;
+  android.media.soundtrigger.SoundModelType type = android.media.soundtrigger.SoundModelType.INVALID;
+  boolean captureAvailable;
+  int captureDelayMs;
+  int capturePreambleMs;
+  boolean triggerInData;
+  @nullable android.media.audio.common.AudioConfig audioConfig;
+  byte[] data;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionMode.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionMode.aidl
new file mode 100644
index 0000000..5882910
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum RecognitionMode {
+  VOICE_TRIGGER = 1,
+  USER_IDENTIFICATION = 2,
+  USER_AUTHENTICATION = 4,
+  GENERIC_TRIGGER = 8,
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionStatus.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionStatus.aidl
new file mode 100644
index 0000000..7881c28
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/RecognitionStatus.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum RecognitionStatus {
+  INVALID = -1,
+  SUCCESS = 0,
+  ABORTED = 1,
+  FAILURE = 2,
+  FORCED = 3,
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/SoundModel.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/SoundModel.aidl
new file mode 100644
index 0000000..fe38264
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/SoundModel.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable SoundModel {
+  android.media.soundtrigger.SoundModelType type = android.media.soundtrigger.SoundModelType.INVALID;
+  String uuid;
+  String vendorUuid;
+  @nullable ParcelFileDescriptor data;
+  int dataSize;
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/SoundModelType.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/SoundModelType.aidl
new file mode 100644
index 0000000..ac78641
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/SoundModelType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum SoundModelType {
+  INVALID = -1,
+  KEYPHRASE = 0,
+  GENERIC = 1,
+}
diff --git a/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Status.aidl b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Status.aidl
new file mode 100644
index 0000000..29f3167
--- /dev/null
+++ b/media/aidl_api/android.media.soundtrigger.types/current/android/media/soundtrigger/Status.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.soundtrigger;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum Status {
+  INVALID = -1,
+  SUCCESS = 0,
+  RESOURCE_CONTENTION = 1,
+  OPERATION_NOT_SUPPORTED = 2,
+  TEMPORARY_PERMISSION_DENIED = 3,
+  DEAD_OBJECT = 4,
+  INTERNAL_ERROR = 5,
+}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index a031b4c..9e657a9 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -334,6 +334,14 @@
     };
 
     /**
+     * @hide
+     */
+    @TestApi
+    public static int[] getSdkUsages() {
+        return SDK_USAGES;
+    }
+
+    /**
      * Flag defining a behavior where the audibility of the sound will be ensured by the system.
      */
     public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b7ea14e..f2078a1 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -387,6 +387,18 @@
      */
     @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
 
+    /** @hide */
+    private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
+            AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
+            AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
+            AudioManager.STREAM_DTMF,  AudioManager.STREAM_ACCESSIBILITY };
+
+    /** @hide */
+    @TestApi
+    public static final int[] getPublicStreamTypes() {
+        return PUBLIC_STREAM_TYPES;
+    }
+
     /**
      * Increase the ringer volume.
      *
@@ -918,8 +930,8 @@
     public void adjustStreamVolume(int streamType, int direction, int flags) {
         final IAudioService service = getService();
         try {
-            service.adjustStreamVolume(streamType, direction, flags,
-                    getContext().getOpPackageName());
+            service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
+                    getContext().getOpPackageName(), getContext().getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -989,7 +1001,7 @@
         final IAudioService service = getService();
         try {
             service.setMasterMute(mute, flags, getContext().getOpPackageName(),
-                    UserHandle.getCallingUserId());
+                    UserHandle.getCallingUserId(), getContext().getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1071,6 +1083,7 @@
      * @return The minimum valid volume index for the stream.
      * @see #getStreamVolume(int)
      */
+    @TestApi
     public int getStreamMinVolumeInt(int streamType) {
         final IAudioService service = getService();
         try {
@@ -1241,7 +1254,8 @@
     public void setStreamVolume(int streamType, int index, int flags) {
         final IAudioService service = getService();
         try {
-            service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());
+            service.setStreamVolumeWithAttribution(streamType, index, flags,
+                    getContext().getOpPackageName(), getContext().getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1266,7 +1280,7 @@
         final IAudioService service = getService();
         try {
             service.setVolumeIndexForAttributes(attr, index, flags,
-                                                getContext().getOpPackageName());
+                    getContext().getOpPackageName(), getContext().getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2726,7 +2740,7 @@
         final IAudioService service = getService();
         try {
             service.setMicrophoneMute(on, getContext().getOpPackageName(),
-                    UserHandle.getCallingUserId());
+                    UserHandle.getCallingUserId(), getContext().getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4253,7 +4267,9 @@
                         afr.getFocusGain(), mICallBack,
                         mAudioFocusDispatcher,
                         clientId,
-                        getContext().getOpPackageName() /* package name */, afr.getFlags(),
+                        getContext().getOpPackageName() /* package name */,
+                        getContext().getAttributionTag(),
+                        afr.getFlags(),
                         ap != null ? ap.cb() : null,
                         sdk);
             } catch (RemoteException e) {
@@ -4358,6 +4374,7 @@
                     durationHint, mICallBack, null,
                     AudioSystem.IN_VOICE_COMM_FOCUS_ID,
                     getContext().getOpPackageName(),
+                    getContext().getAttributionTag(),
                     AUDIOFOCUS_FLAG_LOCK,
                     null /* policy token */, 0 /* sdk n/a here*/);
         } catch (RemoteException e) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8012f03..321db4e 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2051,7 +2051,8 @@
     };
 
     /** @hide */
-    public static String streamToString(int stream) {
+    @TestApi
+    public static @NonNull String streamToString(int stream) {
         if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
         if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
         return "UNKNOWN_STREAM_" + stream;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index c08c368..357c414 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -77,15 +77,17 @@
     oneway void playerSessionId(in int piid, in int sessionId);
 
     // Java-only methods below.
-
-    oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
-            String callingPackage, String caller);
-
     void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
 
+    void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags,
+            in String callingPackage, in String attributionTag);
+
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     void setStreamVolume(int streamType, int index, int flags, String callingPackage);
 
+    void setStreamVolumeWithAttribution(int streamType, int index, int flags,
+            in String callingPackage, in String attributionTag);
+
     oneway void handleVolumeKey(in KeyEvent event, boolean isOnTv,
             String callingPackage, String caller);
 
@@ -95,7 +97,8 @@
 
     boolean isMasterMute();
 
-    void setMasterMute(boolean mute, int flags, String callingPackage, int userId);
+    void setMasterMute(boolean mute, int flags, String callingPackage, int userId,
+            in String attributionTag);
 
     @UnsupportedAppUsage
     int getStreamVolume(int streamType);
@@ -107,7 +110,8 @@
 
     List<AudioVolumeGroup> getAudioVolumeGroups();
 
-    void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags, String callingPackage);
+    void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags,
+            String callingPackage, in String attributionTag);
 
     int getVolumeIndexForAttributes(in AudioAttributes aa);
 
@@ -125,7 +129,7 @@
 
     boolean isMicrophoneMuted();
 
-    void setMicrophoneMute(boolean on, String callingPackage, int userId);
+    void setMicrophoneMute(boolean on, String callingPackage, int userId, in String attributionTag);
 
     oneway void setMicrophoneMuteFromSwitch(boolean on);
 
@@ -182,8 +186,8 @@
     boolean isBluetoothA2dpOn();
 
     int requestAudioFocus(in AudioAttributes aa, int durationHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
-            IAudioPolicyCallback pcb, int sdk);
+            IAudioFocusDispatcher fd, in String clientId, in String callingPackageName,
+            in String attributionTag, int flags, IAudioPolicyCallback pcb, int sdk);
 
     int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, in AudioAttributes aa,
             in String callingPackageName);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 1616c03..bac44ad 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -399,7 +399,7 @@
      * <p>The number and meaning of the planes in an Image are determined by the
      * format of the Image.</p>
      *
-     * <p>Once the Image has been closed, any access to the the plane's
+     * <p>Once the Image has been closed, any access to the plane's
      * ByteBuffer will fail.</p>
      *
      * @see #getFormat
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index cc05ecd..521cbcb 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1695,7 +1695,6 @@
     private static final int CB_ERROR = 3;
     private static final int CB_OUTPUT_FORMAT_CHANGE = 4;
 
-
     private class EventHandler extends Handler {
         private MediaCodec mCodec;
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 4f761ba..ccd830a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -19,7 +19,6 @@
 import static android.Manifest.permission.BIND_IMS_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
-import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -4308,7 +4307,7 @@
     @RequiresPermission(BIND_IMS_SERVICE)
     public void setOnRtpRxNoticeListener(
             @NonNull Context context,
-            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Executor executor,
             @NonNull OnRtpRxNoticeListener listener) {
         Objects.requireNonNull(context);
         Preconditions.checkArgument(
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 341bb8d..f49e045 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -171,8 +171,12 @@
     }
 
     /**
+     *
      * Sets the {@link LogSessionId} for MediaRecorder.
      *
+     * <p>The log session ID is a random 32-byte hexadecimal string that is used for monitoring the
+     * MediaRecorder performance.</p>
+     *
      * @param id the global ID for monitoring the MediaRecorder performance
      */
     public void setLogSessionId(@NonNull LogSessionId id) {
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 345d9b2..4de63f9 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -2034,8 +2034,8 @@
         public void requestSetVolume(int volume) {
             if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
                 try {
-                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0,
-                            ActivityThread.currentPackageName());
+                    sStatic.mAudioService.setStreamVolumeWithAttribution(mPlaybackStream, volume, 0,
+                            ActivityThread.currentPackageName(), null);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
@@ -2053,8 +2053,8 @@
                 try {
                     final int volume =
                             Math.max(0, Math.min(getVolume() + direction, getVolumeMax()));
-                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0,
-                            ActivityThread.currentPackageName());
+                    sStatic.mAudioService.setStreamVolumeWithAttribution(mPlaybackStream, volume, 0,
+                            ActivityThread.currentPackageName(), null);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 0c73348..d00e5b5 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -113,12 +113,10 @@
      */
     public static final int MIX_TYPE_INVALID = -1;
     /**
-     * @hide
      * Mix type indicating playback streams are mixed.
      */
     public static final int MIX_TYPE_PLAYERS = 0;
     /**
-     * @hide
      * Mix type indicating recording streams are mixed.
      */
     public static final int MIX_TYPE_RECORDERS = 1;
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index abbcc66..99ddff2 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -16,6 +16,9 @@
 
 package android.media.audiopolicy;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -24,6 +27,7 @@
 import android.os.Parcel;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Objects;
@@ -199,7 +203,19 @@
     }
 
     private final int mTargetMixType;
-    int getTargetMixType() { return mTargetMixType; }
+
+    /** @hide */
+    @IntDef({AudioMix.MIX_TYPE_PLAYERS, AudioMix.MIX_TYPE_RECORDERS})
+    @Retention(SOURCE)
+    public @interface MixType {}
+
+    /**
+     * Gets target mix type of the mixing rule.
+     */
+    public @MixType int getTargetMixType() {
+        return mTargetMixType;
+    }
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private final ArrayList<AudioMixMatchCriterion> mCriteria;
     /** @hide */
@@ -469,17 +485,24 @@
         }
 
         /**
-         * Set target mix type of the mixing rule.
+         * Sets target mix type of the mixing rule.
          *
-         * <p>Note: If the mix type was not specified, it will be decided automatically by mixing
-         * rule. For {@link #RULE_MATCH_UID}, the default type is {@link AudioMix#MIX_TYPE_PLAYERS}.
+         * <p>Note: If the mix type was not specified, it will be decided automatically by matched
+         * mixing rule. For example, {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE} or {@link
+         * AudioMixingRule#RULE_MATCH_USERID} applied {@link AudioMix#MIX_TYPE_PLAYERS}, {@link
+         * AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} applied {@link
+         * AudioMix#MIX_TYPE_RECORDERS}. For {@link AudioMixingRule#RULE_MATCH_UID}, the mix type
+         * could be {@link AudioMix#MIX_TYPE_PLAYERS} or {@link AudioMix#MIX_TYPE_RECORDERS}, and
+         * {@link AudioMix#MIX_TYPE_PLAYERS} is the default value.
          *
          * @param mixType {@link AudioMix#MIX_TYPE_PLAYERS} or {@link AudioMix#MIX_TYPE_RECORDERS}
          * @return the same Builder instance.
-         *
-         * @hide
          */
-        public @NonNull Builder setTargetMixType(int mixType) {
+        public @NonNull Builder setTargetMixType(@MixType int mixType) {
+            if (mixType != AudioMix.MIX_TYPE_PLAYERS && mixType != AudioMix.MIX_TYPE_RECORDERS) {
+                throw new IllegalArgumentException("Illegal argument for mix type");
+            }
+
             mTargetMixType = mixType;
             Log.i("AudioMixingRule", "Builder setTargetMixType " + mixType);
             return this;
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index fca3498..31d5967 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.media.AudioAttributes;
 import android.media.AudioSystem;
 import android.media.MediaRecorder;
@@ -240,6 +241,7 @@
      * @return the legacy stream type relevant for the given {@link AudioAttributes}.
      *         If none is found, it return DEFAULT stream type.
      */
+    @TestApi
     public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) {
         Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
         for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
@@ -273,6 +275,7 @@
      * @return the volume group id relevant for the given streamType.
      *         If none is found, {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} is returned.
      */
+    @TestApi
     public int getVolumeGroupIdForLegacyStreamType(int streamType) {
         for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
             if (aag.supportsStreamType(streamType)) {
@@ -288,6 +291,7 @@
      * @return the volume group id associated with the given audio attributes if found,
      *         {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} otherwise.
      */
+    @TestApi
     public int getVolumeGroupIdForAudioAttributes(@NonNull AudioAttributes aa) {
         Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
         for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
@@ -352,11 +356,19 @@
      * @hide
      * Default attributes, with default source to be aligned with native.
      */
-    public static final @NonNull AudioAttributes sDefaultAttributes =
+    private static final @NonNull AudioAttributes DEFAULT_ATTRIBUTES =
             new AudioAttributes.Builder().setCapturePreset(MediaRecorder.AudioSource.DEFAULT)
                                          .build();
 
     /**
+     * @hide
+     */
+    @TestApi
+    public static @NonNull AudioAttributes getDefaultAttributes() {
+        return DEFAULT_ATTRIBUTES;
+    }
+
+    /**
      * To avoid duplicating the logic in java and native, we shall make use of
      * native API native_get_product_strategies_from_audio_attributes
      * Keep in sync with frameworks/av/media/libaudioclient/AudioProductStrategy::attributesMatches
@@ -369,7 +381,7 @@
         Preconditions.checkNotNull(attr, "attr must not be null");
         String refFormattedTags = TextUtils.join(";", refAttr.getTags());
         String cliFormattedTags = TextUtils.join(";", attr.getTags());
-        if (refAttr.equals(sDefaultAttributes)) {
+        if (refAttr.equals(DEFAULT_ATTRIBUTES)) {
             return false;
         }
         return ((refAttr.getSystemUsage() == AudioAttributes.USAGE_UNKNOWN)
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 6b329f8..b1baf94 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -23,6 +23,8 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -39,6 +41,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Xml;
 import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -99,6 +102,7 @@
     private int mSurfaceWidth;
     private int mSurfaceHeight;
     private final AttributeSet mAttrs;
+    private final XmlResourceParser mParser;
     private final int mDefStyleAttr;
     private int mWindowZOrder;
     private boolean mUseRequestedSurfaceLayout;
@@ -168,7 +172,16 @@
 
     public TvView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mAttrs = attrs;
+        int sourceResId = Resources.getAttributeSetSourceResId(attrs);
+        if (sourceResId != Resources.ID_NULL) {
+            Log.d(TAG, "Build local AttributeSet");
+            mParser  = context.getResources().getXml(sourceResId);
+            mAttrs = Xml.asAttributeSet(mParser);
+        } else {
+            Log.d(TAG, "Use passed in AttributeSet");
+            mParser = null;
+            mAttrs = attrs;
+        }
         mDefStyleAttr = defStyleAttr;
         resetSurfaceView();
         mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index ee70714..e8ef464 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -46,6 +46,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -112,21 +113,34 @@
     /**
      * All the info about a connection.
      */
-    private class ConnectionRecord implements IBinder.DeathRecipient {
-        String pkg;
-        int uid;
-        int pid;
-        Bundle rootHints;
-        IMediaBrowserServiceCallbacks callbacks;
-        BrowserRoot root;
-        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
+    private static class ConnectionRecord implements IBinder.DeathRecipient {
+        public final MediaBrowserService service;
+        public final String pkg;
+        public final int pid;
+        public final int uid;
+        public final Bundle rootHints;
+        public final IMediaBrowserServiceCallbacks callbacks;
+        public final BrowserRoot root;
+        public final HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
+
+        ConnectionRecord(
+                MediaBrowserService service, String pkg, int pid, int uid, Bundle rootHints,
+                IMediaBrowserServiceCallbacks callbacks, BrowserRoot root) {
+            this.service = service;
+            this.pkg = pkg;
+            this.pid = pid;
+            this.uid = uid;
+            this.rootHints = rootHints;
+            this.callbacks = callbacks;
+            this.root = root;
+        }
 
         @Override
         public void binderDied() {
-            mHandler.post(new Runnable() {
+            service.mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mConnections.remove(callbacks.asBinder());
+                    service.mConnections.remove(callbacks.asBinder());
                 }
             });
         }
@@ -199,39 +213,46 @@
         }
     }
 
-    private class ServiceBinder extends IMediaBrowserService.Stub {
+    private static class ServiceBinder extends IMediaBrowserService.Stub {
+        private WeakReference<MediaBrowserService> mService;
+
+        private ServiceBinder(MediaBrowserService service) {
+            mService = new WeakReference(service);
+        }
+
         @Override
         public void connect(final String pkg, final Bundle rootHints,
                 final IMediaBrowserServiceCallbacks callbacks) {
+            MediaBrowserService service = mService.get();
+            if (service == null) {
+                return;
+            }
 
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-            if (!isValidPackage(pkg, uid)) {
+            if (!service.isValidPackage(pkg, uid)) {
                 throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
                         + " package=" + pkg);
             }
 
-            mHandler.post(new Runnable() {
+            service.mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         final IBinder b = callbacks.asBinder();
 
                         // Clear out the old subscriptions. We are getting new ones.
-                        mConnections.remove(b);
+                        service.mConnections.remove(b);
 
-                        final ConnectionRecord connection = new ConnectionRecord();
-                        connection.pkg = pkg;
-                        connection.pid = pid;
-                        connection.uid = uid;
-                        connection.rootHints = rootHints;
-                        connection.callbacks = callbacks;
-
-                        mCurConnection = connection;
-                        connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
-                        mCurConnection = null;
+                        // Temporarily sets a placeholder ConnectionRecord to make
+                        // getCurrentBrowserInfo() work in onGetRoot().
+                        service.mCurConnection =
+                                new ConnectionRecord(
+                                        service, pkg, pid, uid, rootHints, callbacks, null);
+                        BrowserRoot root = service.onGetRoot(pkg, uid, rootHints);
+                        service.mCurConnection = null;
 
                         // If they didn't return something, don't allow this client.
-                        if (connection.root == null) {
+                        if (root == null) {
                             Log.i(TAG, "No root for client " + pkg + " from service "
                                     + getClass().getName());
                             try {
@@ -242,16 +263,19 @@
                             }
                         } else {
                             try {
-                                mConnections.put(b, connection);
+                                ConnectionRecord connection =
+                                        new ConnectionRecord(
+                                                service, pkg, pid, uid, rootHints, callbacks, root);
+                                service.mConnections.put(b, connection);
                                 b.linkToDeath(connection, 0);
-                                if (mSession != null) {
+                                if (service.mSession != null) {
                                     callbacks.onConnect(connection.root.getRootId(),
-                                            mSession, connection.root.getExtras());
+                                            service.mSession, connection.root.getExtras());
                                 }
                             } catch (RemoteException ex) {
                                 Log.w(TAG, "Calling onConnect() failed. Dropping client. "
                                         + "pkg=" + pkg);
-                                mConnections.remove(b);
+                                service.mConnections.remove(b);
                             }
                         }
                     }
@@ -260,13 +284,18 @@
 
         @Override
         public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
+            MediaBrowserService service = mService.get();
+            if (service == null) {
+                return;
+            }
+
+            service.mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         final IBinder b = callbacks.asBinder();
 
                         // Clear out the old subscriptions. We are getting new ones.
-                        final ConnectionRecord old = mConnections.remove(b);
+                        final ConnectionRecord old = service.mConnections.remove(b);
                         if (old != null) {
                             // TODO
                             old.callbacks.asBinder().unlinkToDeath(old, 0);
@@ -283,20 +312,25 @@
         @Override
         public void addSubscription(final String id, final IBinder token, final Bundle options,
                 final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
+            MediaBrowserService service = mService.get();
+            if (service == null) {
+                return;
+            }
+
+            service.mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         final IBinder b = callbacks.asBinder();
 
                         // Get the record for the connection
-                        final ConnectionRecord connection = mConnections.get(b);
+                        final ConnectionRecord connection = service.mConnections.get(b);
                         if (connection == null) {
                             Log.w(TAG, "addSubscription for callback that isn't registered id="
                                     + id);
                             return;
                         }
 
-                        MediaBrowserService.this.addSubscription(id, connection, token, options);
+                        service.addSubscription(id, connection, token, options);
                     }
                 });
         }
@@ -310,18 +344,23 @@
         @Override
         public void removeSubscription(final String id, final IBinder token,
                 final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
+            MediaBrowserService service = mService.get();
+            if (service == null) {
+                return;
+            }
+
+            service.mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     final IBinder b = callbacks.asBinder();
 
-                    ConnectionRecord connection = mConnections.get(b);
+                    ConnectionRecord connection = service.mConnections.get(b);
                     if (connection == null) {
                         Log.w(TAG, "removeSubscription for callback that isn't registered id="
                                 + id);
                         return;
                     }
-                    if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
+                    if (!service.removeSubscription(id, connection, token)) {
                         Log.w(TAG, "removeSubscription called for " + id
                                 + " which is not subscribed");
                     }
@@ -332,16 +371,21 @@
         @Override
         public void getMediaItem(final String mediaId, final ResultReceiver receiver,
                 final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
+            MediaBrowserService service = mService.get();
+            if (service == null) {
+                return;
+            }
+
+            service.mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     final IBinder b = callbacks.asBinder();
-                    ConnectionRecord connection = mConnections.get(b);
+                    ConnectionRecord connection = service.mConnections.get(b);
                     if (connection == null) {
                         Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId);
                         return;
                     }
-                    performLoadItem(mediaId, connection, receiver);
+                    service.performLoadItem(mediaId, connection, receiver);
                 }
             });
         }
@@ -350,7 +394,7 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        mBinder = new ServiceBinder();
+        mBinder = new ServiceBinder(this);
     }
 
     @Override
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 7c5f58e..116237f 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -282,7 +282,6 @@
     return status;
 }
 
-
 status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
     return mImpl->getSampleMeta(sampleMeta);
 }
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java
index 1131c62..27cf943 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java
@@ -255,7 +255,7 @@
         AudioVolumeGroupCallbackHelper vgCbReceiver = new AudioVolumeGroupCallbackHelper();
         mAudioManager.registerVolumeGroupCallback(mContext.getMainExecutor(), vgCbReceiver);
 
-        final List<Integer> publicStreams = Ints.asList(PUBLIC_STREAM_TYPES);
+        final List<Integer> publicStreams = Ints.asList(AudioManager.getPublicStreamTypes());
         try {
             // Validate Audio Volume Groups callback reception
             for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java
index c0f596b..0e918d1 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertNotEquals;
 
 import android.media.AudioAttributes;
+import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.audiopolicy.AudioProductStrategy;
 import android.media.audiopolicy.AudioVolumeGroup;
@@ -71,7 +72,7 @@
         assertNotNull(audioProductStrategies);
         assertTrue(audioProductStrategies.size() > 0);
 
-        for (final int streamType : PUBLIC_STREAM_TYPES) {
+        for (final int streamType : AudioManager.getPublicStreamTypes()) {
             AudioAttributes aaFromStreamType =
                     AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
                             streamType);
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java
index a17d65c..b30ef30 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java
@@ -37,15 +37,10 @@
     // Default matches the invalid (empty) attributes from native.
     // The difference is the input source default which is not aligned between native and java
     public static final AudioAttributes sDefaultAttributes =
-            AudioProductStrategy.sDefaultAttributes;
+            AudioProductStrategy.getDefaultAttributes();
 
     public static final AudioAttributes sInvalidAttributes = new AudioAttributes.Builder().build();
 
-    public final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
-            AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
-            AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
-            AudioManager.STREAM_DTMF,  AudioManager.STREAM_ACCESSIBILITY };
-
     public AudioVolumesTestBase() {
         super("com.android.audiopolicytest", AudioPolicyTest.class);
     }
@@ -63,7 +58,7 @@
             }
             AudioAttributes avgAttributes = sDefaultAttributes;
             for (final AudioAttributes aa : avg.getAudioAttributes()) {
-                if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
+                if (!aa.equals(AudioProductStrategy.getDefaultAttributes())) {
                     avgAttributes = aa;
                     break;
                 }
@@ -89,7 +84,7 @@
                     assertTrue(!avg.getAudioAttributes().isEmpty());
                     AudioAttributes avgAttributes = sDefaultAttributes;
                     for (final AudioAttributes aa : avg.getAudioAttributes()) {
-                        if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
+                        if (!aa.equals(AudioProductStrategy.getDefaultAttributes())) {
                             avgAttributes = aa;
                             break;
                         }
@@ -114,7 +109,7 @@
 
         // Store the original volumes that that they can be recovered in tearDown().
         mOriginalStreamVolumes.clear();
-        for (int streamType : PUBLIC_STREAM_TYPES) {
+        for (int streamType : AudioManager.getPublicStreamTypes()) {
             mOriginalStreamVolumes.put(streamType, mAudioManager.getStreamVolume(streamType));
         }
         // Store the original volume per attributes so that they can be recovered in tearDown()
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index cdf4851..3faed55 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Stel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Jy het <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nee, dankie"</string>
+    <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_summary" msgid="2059360676631420073">"Hierdie program is nodig om jou <xliff:g id="PROFILE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index a03ea0d..99466d7 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; እንዲያስተዳድር ያቀናብሩት"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ለማስተዳደር ያስፈልጋል። <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"አዎ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"አይ፣ አመሰግናለሁ"</string>
+    <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_summary" msgid="2059360676631420073">"የእርስዎን <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ለማስተዳደር ይህ መተግበሪያ ያስፈልጋል <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 970c46b..c3f1e73 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"‏اضبط &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g> على &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"يجب توفّر تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"نعم"</string>
-    <string name="consent_no" msgid="1335543792857823917">"لا، شكرًا"</string>
+    <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_summary" msgid="2059360676631420073">"هذا التطبيق مطلوب لإدارة <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"السماح"</string>
+    <string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 477844c..2a2bc25 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ছেট কৰক - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ আৱশ্যক। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"হয়"</string>
-    <string name="consent_no" msgid="1335543792857823917">"নালাগে, ধন্যবাদ"</string>
+    <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_summary" msgid="2059360676631420073">"আপোনাৰ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্‌টোৰ আৱশ্যক। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string>
+    <string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index f10c639..4710dbe 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizin &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tərəfindən idarə olunmasını ayarlayın - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizi idarə etmək üçün <xliff:g id="APP_NAME">%1$s</xliff:g> tələb olunur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Bəli"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Xeyr, çox sağolun"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin &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_summary" msgid="2059360676631420073">"Bu tətbiq <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilinizi idarə etmək üçün lazımdır. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
+    <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index e8542f3..d687b05 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Podesite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je neophodna za upravljanje profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
+    <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_summary" msgid="2059360676631420073">"Ova aplikacija je potrebna za upravljanje profilom <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 13be6f2..2236052f5 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Для кіравання прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" патрабуецца праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Так"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Не, дзякуй"</string>
+    <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_summary" msgid="2059360676631420073">"Гэта праграма неабходная для кіравання профілем \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 3bda5e6..996ca90 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Задайте &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството ви (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"За управление на <xliff:g id="PROFILE_NAME">%2$s</xliff:g> се изисква <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Не, благодаря"</string>
+    <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_summary" msgid="2059360676631420073">"Това приложение е необходимо за управление на <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Забраняване"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index d3bc515..16d25ce 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -19,9 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
-    <string name="profile_name_watch" msgid="576290739483672360">"দেখুন"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>-কে আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g>.ম্যানেজ করতে দিতে হবে। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"হ্যাঁ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"না থাক"</string>
+    <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
+    <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_summary" msgid="2059360676631420073">"আপনার <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ম্যানেজ করতে এই অ্যাপটি প্রয়োজন। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string>
+    <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 905b306..10f753c 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Potrebna je aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> za upravljanje uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
+    <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_summary" msgid="2059360676631420073">"Ova aplikacija je potrebna za upravljanje profilom: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 86dc694..e55a033 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Defineix que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"L\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> és necessària per gestionar el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sí"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, gràcies"</string>
+    <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_summary" msgid="2059360676631420073">"Aquesta aplicació es necessita per gestionar el teu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
+    <string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 389ccd0..48fbda1 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Nastavit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ke správě tohoto zařízení: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Ke správě profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potřeba aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ano"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ne, díky"</string>
+    <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_summary" msgid="2059360676631420073">"Tato aplikace je nutná pro správu profilu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 5a31f9b..446c301 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -16,12 +16,12 @@
 
 <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="4470785958457506021">"Medfølgende enhedshåndtering"</string>
+    <string name="app_label" msgid="4470785958457506021">"Medfølgende enhedsadministrator"</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>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Angiv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; til administration af: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er nødvendig for at administrere: <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nej tak"</string>
+    <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_summary" msgid="2059360676631420073">"Du skal bruge denne app for at administrere dit <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index b643eb2..33d831d 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zum Verwalten deines Geräts (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) festlegen – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist erforderlich, um dein Gerät (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) zu verwalten. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nein danke"</string>
+    <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_summary" msgid="2059360676631420073">"Diese App wird zur Verwaltung des Profils „<xliff:g id="PROFILE_NAME">%1$s</xliff:g>“ benötigt. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 60de2ff..7a78c06 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Ορίστε μια εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; για διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απαιτείται για τη διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ναι"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Όχι, ευχαριστώ"</string>
+    <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_summary" msgid="2059360676631420073">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση του προφίλ σας <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index 2fed1ae..a6ebe65 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -20,8 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 2fed1ae..a6ebe65 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -20,8 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index 2fed1ae..a6ebe65 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -20,8 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index 2fed1ae..a6ebe65 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -20,8 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index f3c4b1d..6cc56a4 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -20,8 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎Choose a ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to be managed by &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎device‎‏‎‎‏‎"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎watch‎‏‎‎‏‎"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎Set &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to manage your ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ - &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎Yes‎‏‎‎‏‎"</string>
-    <string name="consent_no" msgid="1335543792857823917">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎No thanks‎‏‎‎‏‎"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to manage your &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎This app is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎Allow‎‏‎‎‏‎"</string>
+    <string name="consent_no" msgid="2640796915611404382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎Don’t allow‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 4fbb57e..dc13159 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para administrar <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Se requiere <xliff:g id="APP_NAME">%1$s</xliff:g> para administrar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sí"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string>
+    <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_summary" msgid="2059360676631420073">"Esta app es necesaria para administrar tu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index 5ca9305..7e37c1d 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Haz que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestione tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Se necesita <xliff:g id="APP_NAME">%1$s</xliff:g> para gestionar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sí"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string>
+    <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_summary" msgid="2059360676631420073">"Se necesita esta aplicación para gestionar tu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 357f052..399556d 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Määrake rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; haldama teie seadet <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> on vajalik teie seadme <xliff:g id="PROFILE_NAME">%2$s</xliff:g> haldamiseks. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Jah"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Tänan, ei"</string>
+    <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_summary" msgid="2059360676631420073">"Seda rakendust on vaja teie profiili <xliff:g id="PROFILE_NAME">%1$s</xliff:g> haldamiseks. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 14c7154..764505e 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Konfiguratu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;) kudea dezan"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> erabili behar duzu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kudeatzeko. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Bai"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ez"</string>
+    <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_summary" msgid="2059360676631420073">"Aplikazioa <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kudeatzeko beharrezkoa da. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 6bb9620..07d04aa 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"‏تنظیم &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‏&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> به <xliff:g id="APP_NAME">%1$s</xliff:g> نیاز دارید. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"بله"</string>
-    <string name="consent_no" msgid="1335543792857823917">"نه متشکرم"</string>
+    <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_summary" msgid="2059360676631420073">"این برنامه برای مدیریت <xliff:g id="PROFILE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"مجاز بودن"</string>
+    <string name="consent_no" msgid="2640796915611404382">"مجاز نبودن"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 5a9c1cd..528d16c 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Aseta &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnoijaksi – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> tarvitaan profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnointiin. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Kyllä"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ei kiitos"</string>
+    <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_summary" msgid="2059360676631420073">"Profiilin (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) ylläpitoon tarvitaan tätä sovellusta. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index b31babd..2cf872c 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Utiliser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est requise pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Oui"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Non merci"</string>
+    <string name="confirmation_title" msgid="8455544820286920304">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Cette application est nécessaire pour gérer votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 08c93a2c..ba2fc8e 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Définir &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour la gestion de votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> est requis pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Oui"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Non, merci"</string>
+    <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_summary" msgid="2059360676631420073">"Cette appli est nécessaire pour gérer votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index c95b90e..5f9a8d7 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Define a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para a xestión do teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>): &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Necesítase a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> para xestionar o teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Si"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Non, grazas"</string>
+    <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_summary" msgid="2059360676631420073">"Esta aplicación é necesaria para xestionar o teu perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 7e41042..71cf012 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ને મેનેજ કરવા માટે <xliff:g id="APP_NAME">%1$s</xliff:g> જરૂરી છે. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"હા"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ના, આભાર"</string>
+    <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_summary" msgid="2059360676631420073">"તમારી <xliff:g id="PROFILE_NAME">%1$s</xliff:g> મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
+    <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index ac95cc6..d4dd1cb 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"अपने <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"आपके <xliff:g id="PROFILE_NAME">%2$s</xliff:g> को प्रबंधित करने के लिए, <xliff:g id="APP_NAME">%1$s</xliff:g> की ज़रूरत है. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"हां"</string>
-    <string name="consent_no" msgid="1335543792857823917">"नहीं, रहने दें"</string>
+    <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_summary" msgid="2059360676631420073">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> को मैनेज करने के लिए, यह ऐप्लिकेशन ज़रूरी है. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
+    <string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index df8451f..87c5ae2 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> –- &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> potrebna je za upravljanje vašim <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
+    <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_summary" msgid="2059360676631420073">"Ta je aplikacija potrebna za upravljanje vašim profilom <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index ff1c6c5..c7ceb38 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazás beállítása a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;) kezelésére"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Szükség van a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásra a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kezeléséhez. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Igen"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nem"</string>
+    <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_summary" msgid="2059360676631420073">"Szükség van erre az alkalmazásra a következő kezeléséhez: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index 194223d..26f7990 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Ընտրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը որպես <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ի կառավարիչ․ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Ձեր <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ը կառավարելու համար անհրաժեշտ է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը։ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Այո"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ոչ, շնորհակալություն"</string>
+    <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_summary" msgid="2059360676631420073">"Այս հավելվածն անհրաժեշտ է <xliff:g id="PROFILE_NAME">%1$s</xliff:g> սարքը կամ պրոֆիլը կառավարելու համար։ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 58bf3cb..b0618d4 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Perlu <xliff:g id="APP_NAME">%1$s</xliff:g> untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ya"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Tidak"</string>
+    <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_summary" msgid="2059360676631420073">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index cc5b989..b7d7c6a 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; stjórn á <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er krafist til að stjórna <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Já"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nei, takk"</string>
+    <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_summary" msgid="2059360676631420073">"Þetta forrit er nauðsynlegt til að hafa umsjón með <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 4cbefd8..ce003e7 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"È richiesta l\'app <xliff:g id="APP_NAME">%1$s</xliff:g> per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sì"</string>
-    <string name="consent_no" msgid="1335543792857823917">"No, grazie"</string>
+    <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_summary" msgid="2059360676631420073">"Questa app è necessaria per gestire il tuo <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 8663e56..54c523c 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -17,11 +17,11 @@
 <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="4470785958457506021">"ניהול מכשיר מותאם"</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>
+    <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"‏הגדרה של &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לניהול <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> נדרשת לניהול של <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"כן"</string>
-    <string name="consent_no" msgid="1335543792857823917">"לא תודה"</string>
+    <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_summary" msgid="2059360676631420073">"האפליקציה הזו נחוצה כדי לנהל את ה<xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
+    <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index ca17336..f92fafe 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; で <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; を管理するよう設定する"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> を管理するために <xliff:g id="APP_NAME">%1$s</xliff:g> が必要です。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"はい"</string>
-    <string name="consent_no" msgid="1335543792857823917">"いいえ"</string>
+    <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_summary" msgid="2059360676631420073">"このアプリは <xliff:g id="PROFILE_NAME">%1$s</xliff:g> の管理に必要です。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"許可"</string>
+    <string name="consent_no" msgid="2640796915611404382">"許可しない"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 300c94f..34efdd2 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"დააყენეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, რომ მართოს თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-ის სამართავად საჭიროა <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"დიახ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"არა, გმადლობთ"</string>
+    <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_summary" msgid="2059360676631420073">"ეს აპი საჭიროა თქვენი <xliff:g id="PROFILE_NAME">%1$s</xliff:g>-ს სამართავად. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string>
+    <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 94d6c3e..3c7f697 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) құрылғысын басқаруға рұқсат беру"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> құрылғысын басқару үшін <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Иә"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Жоқ, рақмет"</string>
+    <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_summary" msgid="2059360676631420073">"Бұл қолданба <xliff:g id="PROFILE_NAME">%1$s</xliff:g> профиліңізді басқару үшін қажет. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index db13fe7..74ccd84 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"កំណត់ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"ចាំបាច់ត្រូវមាន <xliff:g id="APP_NAME">%1$s</xliff:g> ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក។ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"បាទ/ចាស"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ទេ អរគុណ"</string>
+    <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_summary" msgid="2059360676631420073">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string>
+    <string name="consent_no" msgid="2640796915611404382">"កុំអនុញ្ញាត"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 0225166..2a82d1f 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <xliff:g id="APP_NAME">%1$s</xliff:g> ಅಗತ್ಯವಿದೆ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ಹೌದು"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ಬೇಡ, ಧನ್ಯವಾದಗಳು"</string>
+    <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_summary" msgid="2059360676631420073">"ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್‌ನ ಅಗತ್ಯವಿದೆ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 1363e57..6ca01bf 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 <xliff:g id="PROFILE_NAME">%2$s</xliff:g>(&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)을(를) 관리하도록 설정"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> 프로필을 관리하려면 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 필요합니다. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"예"</string>
-    <string name="consent_no" msgid="1335543792857823917">"취소"</string>
+    <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_summary" msgid="2059360676631420073">"이 앱은 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 프로필을 관리하는 데 필요합니다. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"허용"</string>
+    <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index c01e235..18d38a8 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; түзмөгүңүздү башкарсын"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> профилиңизди башкаруу үчүн <xliff:g id="APP_NAME">%1$s</xliff:g> керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ооба"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Жок, рахмат"</string>
+    <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_summary" msgid="2059360676631420073">"Бул колдонмо <xliff:g id="PROFILE_NAME">%1$s</xliff:g> профилиңизди башкаруу үчүн керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Уруксат берүү"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 68218dd..a1eb713 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"ຕັ້ງ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານ"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"ຕ້ອງໃຊ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ຂອງທ່ານ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ແມ່ນແລ້ວ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ບໍ່, ຂອບໃຈ"</string>
+    <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_summary" msgid="2059360676631420073">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 5fd8280..65f371d 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -19,9 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</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>
     <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
-    <string name="profile_name_watch" msgid="576290739483672360">"laikrodis"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Nustatyti, kad <xliff:g id="PROFILE_NAME">%2$s</xliff:g> &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; būtų valdomas programos &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Norint valdyti jūsų <xliff:g id="PROFILE_NAME">%2$s</xliff:g>, reikalinga programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Taip"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ne, ačiū"</string>
+    <string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
+    <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_summary" msgid="2059360676631420073">"Ši programa reikalinga norint tvarkyti jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index bf036ec..b18bfe4 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Lietotnes &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iestatīšana profila (<xliff:g id="PROFILE_NAME">%2$s</xliff:g> — &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;) pārvaldībai"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Lai pārvaldītu profilu (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), nepieciešama lietotne <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Jā"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nē, paldies"</string>
+    <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_summary" msgid="2059360676631420073">"Šī lietotne ir nepieciešama jūsu profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) pārvaldībai. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 427ca8f..9d745c4 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Поставете ја &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> е потребна за да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Не, фала"</string>
+    <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_summary" msgid="2059360676631420073">"Апликацијава е потребна за управување со вашиот <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index a48c45f..28c88da 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യുന്നതിന് &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; സജ്ജീകരിക്കുക - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്ന ആപ്പിന് നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യേണ്ടതുണ്ട്. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"വേണം"</string>
-    <string name="consent_no" msgid="1335543792857823917">"വേണ്ട"</string>
+    <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_summary" msgid="2059360676631420073">"നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
+    <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 7ac20e6..11e61d9 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>-аа удирдахын тулд &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-г тохируулна уу - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Таны <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-г удирдахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> шаардлагатай. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Тийм"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Үгүй, баярлалаа"</string>
+    <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_summary" msgid="2059360676631420073">"Энэ апп таны <xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 144698b..c73ed28 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -19,9 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</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>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
-    <string name="profile_name_watch" msgid="576290739483672360">"पाहा"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; सेट करा - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> आवश्यक आहे. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"होय"</string>
-    <string name="consent_no" msgid="1335543792857823917">"नाही, नको"</string>
+    <string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
+    <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_summary" msgid="2059360676631420073">"तुमची <xliff:g id="PROFILE_NAME">%1$s</xliff:g> प्रोफाइल व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string>
+    <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 7bea2c9..d2aebb4 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; anda"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> diperlukan untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> anda. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ya"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Tidak perlu"</string>
+    <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_summary" msgid="2059360676631420073">"Apl ini diperlukan untuk mengurus <xliff:g id="PROFILE_NAME">%1$s</xliff:g> anda. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 9c2783c..45c9d8b 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ကို စီမံခန့်ခွဲရန် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို လိုအပ်ပါသည်။ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
-    <string name="consent_no" msgid="1335543792857823917">"မလိုပါ"</string>
+    <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_summary" msgid="2059360676631420073">"သင်၏ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်ကိုလိုအပ်သည်။ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 26fbb03..af1ffe9 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Angi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> kreves for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nei takk"</string>
+    <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_summary" msgid="2059360676631420073">"Denne appen kreves for å administrere <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index f289b37..b29f94c 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -16,12 +16,12 @@
 
 <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="4470785958457506021">"सहयोगी यन्त्रको प्रबन्धक"</string>
+    <string name="app_label" msgid="4470785958457506021">"सहयोगी डिभाइसको प्रबन्धक"</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>
     <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"आफ्नो <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापन गर्न <xliff:g id="APP_NAME">%1$s</xliff:g> इन्स्टल गर्नु पर्ने हुन्छ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"अँ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"सहमत छुइनँ"</string>
+    <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_summary" msgid="2059360676631420073">"तपाईंको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एपलाई अनुमति दिनु पर्ने हुन्छ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string>
+    <string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 0c9cdffd..a56fb9a 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; instellen om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; te beheren"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Je hebt <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te beheren. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nee, bedankt"</string>
+    <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_summary" msgid="2059360676631420073">"Deze app is vereist om je <xliff:g id="PROFILE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index c8c680f..8e43213 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ସେଟ୍ କରନ୍ତୁ - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆବଶ୍ୟକ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ହଁ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ନା, ଧନ୍ୟବାଦ"</string>
+    <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_summary" msgid="2059360676631420073">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ୍ ଆବଶ୍ୟକ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index 0da9410..54f4f8c 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡਾ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਸੈੱਟ ਕਰੋ"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"ਤੁਹਾਡੇ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਲੋੜ ਹੈ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ਹਾਂ"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
+    <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_summary" msgid="2059360676631420073">"ਤੁਹਾਡੇ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਇਹ ਐਪ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ਇਜਾਜ਼ਤ ਦਿਓ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index b07af57..a989baa 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Ustaw aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> na urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest wymagana do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Tak"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nie, dziękuję"</string>
+    <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_summary" msgid="2059360676631420073">"Ta aplikacja jest niezbędna do zarządzania profilem <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 16906f6..d2724c0 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Defina o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sim"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Agora não"</string>
+    <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_summary" msgid="2059360676631420073">"Esse app é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 745d163..2f5a53b 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Defina a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para gerir o seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessária para gerir o seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sim"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Não, obrigado"</string>
+    <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_summary" msgid="2059360676631420073">"Esta app é necessária para gerir o seu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 16906f6..d2724c0 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Defina o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Sim"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Agora não"</string>
+    <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_summary" msgid="2059360676631420073">"Esse app é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 187cfbdf..4df74de 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Setați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> este necesară pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nu, mulțumesc"</string>
+    <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_summary" msgid="2059360676631420073">"Această aplicație este necesară pentru a gestiona <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permiteți"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nu permiteți"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 8dd9a39..ea372d5 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять устройством &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" необходимо для управления устройством (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Нет"</string>
+    <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_summary" msgid="2059360676631420073">"Это приложение необходимо для управления вашим профилем \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 9e7c02e..a5c2c88 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට සකසන්න - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට <xliff:g id="APP_NAME">%1$s</xliff:g> අවශ්‍යයි. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ඔව්"</string>
-    <string name="consent_no" msgid="1335543792857823917">"එපා, ස්තුතියි"</string>
+    <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_summary" msgid="2059360676631420073">"මෙම යෙදුමට ඔබගේ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> කළමනාකරණය කිරීමට අවශ්‍යයි. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 55a47c2..a9bf77f 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Nastavte aplikáciu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, aby spravovala profil <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Na správu profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potrebná aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Áno"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nie, vďaka"</string>
+    <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_summary" msgid="2059360676631420073">"Táto aplikácia sa vyžaduje na správu profilu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 159afd5..4eb8f50 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Nastavitev aplikacije &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, ki bo upravljala napravo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Za upravljanje naprave <xliff:g id="PROFILE_NAME">%2$s</xliff:g> potrebujete aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
+    <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_summary" msgid="2059360676631420073">"Ta aplikacija je potrebna za upravljanje profila »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>«. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 6fa759c..34357b4 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Cakto &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; që të menaxhojë profilin tënd <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Nevojitet <xliff:g id="APP_NAME">%1$s</xliff:g> për të menaxhuar profilin tënd të <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Po"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Jo, faleminderit"</string>
+    <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_summary" msgid="2059360676631420073">"Ky aplikacion nevojitet për të menaxhuar profilin tënd <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index fdbbe8e..37af185 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Подесите апликацију &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управља профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је неопходна за управљање профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Не, хвала"</string>
+    <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_summary" msgid="2059360676631420073">"Ова апликација је потребна за управљање профилом <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index bfd2516..f78fadf 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Konfigurera &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> krävs för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Nej tack"</string>
+    <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_summary" msgid="2059360676631420073">"Appen behövs för att hantera <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 437ae7f..495c441 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Weka &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ili udhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> linahitajika ili kudhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ndiyo"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Hapana"</string>
+    <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_summary" msgid="2059360676631420073">"Programu hii inahitajika ili udhibiti wasifu wako wa <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 9b4a720..20845bd 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ஐ நிர்வகிக்க <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் வேண்டும். <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ஆம்"</string>
-    <string name="consent_no" msgid="1335543792857823917">"வேண்டாம்"</string>
+    <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_summary" msgid="2059360676631420073">"உங்கள் <xliff:g id="PROFILE_NAME">%1$s</xliff:g> சுயவிவரத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவைப்படுகிறது. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string>
+    <string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 6e785de..c855cf2 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$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_summary" msgid="2009764182871566255">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ను మేనేజ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అవసరం ఉంది. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"అవును"</string>
-    <string name="consent_no" msgid="1335543792857823917">"వద్దు, ధన్యవాదాలు"</string>
+    <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_summary" msgid="2059360676631420073">"మీ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"అనుమతించు"</string>
+    <string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index b727d42..d78ada2 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"ตั้งค่า &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ให้จัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g>ของคุณ - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"ต้องใช้ <xliff:g id="APP_NAME">%1$s</xliff:g> ในการจัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g> <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ใช่"</string>
-    <string name="consent_no" msgid="1335543792857823917">"ไม่เป็นไร"</string>
+    <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_summary" msgid="2059360676631420073">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ของคุณ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index a93282a..03165b4 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Itakda ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Kailangan ang <xliff:g id="APP_NAME">%1$s</xliff:g> para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Oo"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Huwag na lang"</string>
+    <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_summary" msgid="2059360676631420073">"Kinakailangan ang app na ito para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 3abe064..b2c1cf2 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasını, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; cihazınızı yönetecek şekilde ayarlayın"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yönetimi için gereklidir. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Evet"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Hayır, teşekkürler"</string>
+    <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_summary" msgid="2059360676631420073">"Bu uygulama, <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilinizin yönetilmesi için gereklidir. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
+    <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 161d95e..61b78e9 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Налаштуйте додаток &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, щоб керувати своїм пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Щоб керувати своїм пристроєм (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), вам потрібен додаток <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Так"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Ні, дякую"</string>
+    <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_summary" msgid="2059360676631420073">"Цей додаток потрібен, щоб керувати профілем \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index dce1815..ee79921 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"‏اپنے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو سیٹ کریں - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"آپ کے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <xliff:g id="APP_NAME">%1$s</xliff:g> کی ضرورت ہے۔ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"ہاں"</string>
-    <string name="consent_no" msgid="1335543792857823917">"نہیں شکریہ"</string>
+    <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_summary" msgid="2059360676631420073">"اس ایپ کو آپ کے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا نظم کرنے کی ضرورت ہے۔ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string>
+    <string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 2ca27b5..7221b6d 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; qurilmalarini boshqarish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasini sozlang"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> qurilmasini boshqarish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> zarur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Ha"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Kerak emas"</string>
+    <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_summary" msgid="2059360676631420073">"Bu ilova <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 06a1ab6..2819e1d 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Đặt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"Cần có <xliff:g id="APP_NAME">%1$s</xliff:g> để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Có"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Không, cảm ơn"</string>
+    <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_summary" msgid="2059360676631420073">"Cần có ứng dụng này để quản lý <xliff:g id="PROFILE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 12bfcf3..1440c40 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"设为由&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"若要管理<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,您需要使用<xliff:g id="APP_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"好"</string>
-    <string name="consent_no" msgid="1335543792857823917">"不用了"</string>
+    <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_summary" msgid="2059360676631420073">"需要使用此应用,才能管理您的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"允许"</string>
+    <string name="consent_no" msgid="2640796915611404382">"不允许"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 0c583b2..e3f1eb1 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -16,12 +16,12 @@
 
 <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="4470785958457506021">"隨附裝置管理員"</string>
+    <string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</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>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"設定 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 來管理您的 <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"必須使用 <xliff:g id="APP_NAME">%1$s</xliff:g> 來管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"是"</string>
-    <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string>
+    <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_summary" msgid="2059360676631420073">"必須使用此應用程式,才能管理<xliff:g id="PROFILE_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
+    <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 519f0e8..9f4041d 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"授權讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"如要管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,必須使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"是"</string>
-    <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string>
+    <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_summary" msgid="2059360676631420073">"需使用這個應用程式,才能管理「<xliff:g id="PROFILE_NAME">%1$s</xliff:g>」。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
+    <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index 7721b54..dc933ae 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -20,8 +20,8 @@
     <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>
     <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
-    <string name="confirmation_title" msgid="4751119145078041732">"Setha i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuba iphathe i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="profile_summary" msgid="2009764182871566255">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> iyadingeka ukuphatha i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> yakho. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
-    <string name="consent_yes" msgid="4055438216605487056">"Yebo"</string>
-    <string name="consent_no" msgid="1335543792857823917">"Cha ngiyabonga"</string>
+    <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_summary" msgid="2059360676631420073">"I-app iyadingeka ukuphatha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> yakho. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
 </resources>
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java b/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
new file mode 100644
index 0000000..eb1faa0
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Type annotations for constants used in the connectivity API surface.
+ *
+ * The annotations are maintained in a separate class so that it can be built as
+ * a separate library that other modules can build against, as Typedef should not
+ * be exposed as SystemApi.
+ *
+ * @hide
+ */
+public final class ConnectivityAnnotations {
+    private ConnectivityAnnotations() {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
+            ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER,
+            ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY,
+            ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE,
+    })
+    public @interface MultipathPreference {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED,
+            ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED,
+            ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED,
+    })
+    public @interface RestrictBackgroundStatus {}
+}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index a65bf41..2b8f049 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -11,33 +11,6 @@
 
     name: "SettingsLib",
 
-    defaults: [
-        "SettingsLibDependenciesWithoutWifiTracker",
-    ],
-
-    // TODO(b/149540986): revert this change.
-    static_libs: [
-        // All other dependent components should be put in
-        // "SettingsLibDependenciesWithoutWifiTracker".
-        "WifiTrackerLib",
-    ],
-
-    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
-    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
-
-    resource_dirs: ["res"],
-
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-    ],
-
-    min_sdk_version: "29",
-
-}
-
-java_defaults {
-    name: "SettingsLibDependenciesWithoutWifiTracker",
     static_libs: [
         "androidx.annotation_annotation",
         "androidx.legacy_legacy-support-v4",
@@ -48,6 +21,7 @@
         "androidx.mediarouter_mediarouter-nodeps",
         "iconloader",
 
+        "WifiTrackerLibRes",
         "SettingsLibHelpUtils",
         "SettingsLibRestrictedLockUtils",
         "SettingsLibActionBarShadow",
@@ -74,6 +48,19 @@
         "SettingsLibTwoTargetPreference",
         "SettingsLibSettingsTransition",
     ],
+
+    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
+    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
+
+    resource_dirs: ["res"],
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+
+    min_sdk_version: "29",
+
 }
 
 // NOTE: Keep this module in sync with ./common.mk
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-af/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-af/strings.xml
new file mode 100644
index 0000000..d7e778f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Weier"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-am/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-am/strings.xml
new file mode 100644
index 0000000..6701dea
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"አሰናብት"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ar/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ar/strings.xml
new file mode 100644
index 0000000..0f1b9ac
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"إغلاق"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-as/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-as/strings.xml
new file mode 100644
index 0000000..21dd94c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"অগ্ৰাহ্য কৰক"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-az/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-az/strings.xml
new file mode 100644
index 0000000..7f91eb4
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Qapadın"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..ca16c3d
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Odbacite"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-be/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-be/strings.xml
new file mode 100644
index 0000000..b0980ea
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Адхіліць"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-bg/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-bg/strings.xml
new file mode 100644
index 0000000..cccbf96
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Отхвърляне"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml
new file mode 100644
index 0000000..e0dfcf2
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"বাতিল করুন"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-bs/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-bs/strings.xml
new file mode 100644
index 0000000..5e46c6c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Odbacivanje"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ca/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ca/strings.xml
new file mode 100644
index 0000000..81bb048
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignora"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-cs/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-cs/strings.xml
new file mode 100644
index 0000000..ac7623e
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Zavřít"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-da/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-da/strings.xml
new file mode 100644
index 0000000..8c185d9
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Luk"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml
new file mode 100644
index 0000000..006301b
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Schließen"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-el/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-el/strings.xml
new file mode 100644
index 0000000..65843b2
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Παράβλεψη"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-en-rAU/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..418c1d5
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Dismiss"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-en-rCA/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..418c1d5
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Dismiss"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-en-rGB/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..418c1d5
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Dismiss"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-en-rIN/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..418c1d5
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Dismiss"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-en-rXC/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..e2dae5e
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎Dismiss‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-es-rUS/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..4816be6
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Descartar"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-es/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-es/strings.xml
new file mode 100644
index 0000000..5e820238
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Cerrar"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-et/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-et/strings.xml
new file mode 100644
index 0000000..a688723
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Loobu"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-eu/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-eu/strings.xml
new file mode 100644
index 0000000..64dd1c5
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Baztertu"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-fa/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-fa/strings.xml
new file mode 100644
index 0000000..bd8985f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"رد شدن"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-fi/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-fi/strings.xml
new file mode 100644
index 0000000..c384157
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ohita"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-fr-rCA/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..dd5889c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Fermer"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-fr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-fr/strings.xml
new file mode 100644
index 0000000..dd5889c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Fermer"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
new file mode 100644
index 0000000..d787626
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignorar"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml
new file mode 100644
index 0000000..1fe4c5c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"છોડી દો"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-hi/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-hi/strings.xml
new file mode 100644
index 0000000..f66ee7f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"खारिज करें"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-hr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-hr/strings.xml
new file mode 100644
index 0000000..f7e7cd0
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Odbaci"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-hu/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-hu/strings.xml
new file mode 100644
index 0000000..1551c84
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Bezárás"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-hy/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-hy/strings.xml
new file mode 100644
index 0000000..e014cce
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Փակել"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-in/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-in/strings.xml
new file mode 100644
index 0000000..607e811
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Tutup"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-is/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-is/strings.xml
new file mode 100644
index 0000000..4afc614
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Hunsa"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-it/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-it/strings.xml
new file mode 100644
index 0000000..81bb048
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignora"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-iw/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-iw/strings.xml
new file mode 100644
index 0000000..aa4c669
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"סגירה"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ja/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ja/strings.xml
new file mode 100644
index 0000000..b42f6e6
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"閉じる"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ka/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ka/strings.xml
new file mode 100644
index 0000000..7bde8b6
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"უარყოფა"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-kk/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-kk/strings.xml
new file mode 100644
index 0000000..01235e0
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Жабу"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-km/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-km/strings.xml
new file mode 100644
index 0000000..4e14820
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ច្រានចោល"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-kn/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-kn/strings.xml
new file mode 100644
index 0000000..b9a5420
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ವಜಾಗೊಳಿಸಿ"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ko/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ko/strings.xml
new file mode 100644
index 0000000..9b51699
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"닫기"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ky/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ky/strings.xml
new file mode 100644
index 0000000..affb8ec
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Жабуу"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-lo/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-lo/strings.xml
new file mode 100644
index 0000000..7079f7c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ປິດໄວ້"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-lt/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-lt/strings.xml
new file mode 100644
index 0000000..4cee14a
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Atsisakyti"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-lv/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-lv/strings.xml
new file mode 100644
index 0000000..120a762
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Nerādīt"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-mk/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-mk/strings.xml
new file mode 100644
index 0000000..76a4390
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Отфрли"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ml/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ml/strings.xml
new file mode 100644
index 0000000..5a4e14c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-mn/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-mn/strings.xml
new file mode 100644
index 0000000..3974470
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Үл хэрэгсэх"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml
new file mode 100644
index 0000000..4bd4485
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"डिसमिस करा"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ms/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ms/strings.xml
new file mode 100644
index 0000000..290323b
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ketepikan"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-my/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-my/strings.xml
new file mode 100644
index 0000000..52ecc49
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ပယ်ရန်"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-nb/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-nb/strings.xml
new file mode 100644
index 0000000..c1e39a4
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Lukk"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml
new file mode 100644
index 0000000..1510254
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"हटाउनुहोस्"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-nl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-nl/strings.xml
new file mode 100644
index 0000000..920349f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Sluiten"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml
new file mode 100644
index 0000000..36e7d3b
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ଖାରଜ କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-pa/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-pa/strings.xml
new file mode 100644
index 0000000..250ef2e
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ਖਾਰਜ ਕਰੋ"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-pl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-pl/strings.xml
new file mode 100644
index 0000000..9ad630a
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Zamknij"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-pt-rBR/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..80b70ae
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Dispensar"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-pt-rPT/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..d787626
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignorar"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-pt/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-pt/strings.xml
new file mode 100644
index 0000000..80b70ae
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Dispensar"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml
new file mode 100644
index 0000000..18b6a0e
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Respingeți"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ru/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ru/strings.xml
new file mode 100644
index 0000000..b694657
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Закрыть"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-si/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-si/strings.xml
new file mode 100644
index 0000000..d818cf7
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ඉවත ලන්න"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-sk/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-sk/strings.xml
new file mode 100644
index 0000000..4f59f85
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Zavrieť"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-sl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-sl/strings.xml
new file mode 100644
index 0000000..1ca68bf
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Opusti"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-sq/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-sq/strings.xml
new file mode 100644
index 0000000..dbe7927
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Hiq"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-sr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-sr/strings.xml
new file mode 100644
index 0000000..68a2d5b
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Одбаците"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-sv/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-sv/strings.xml
new file mode 100644
index 0000000..ef2df3c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ignorera"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-sw/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-sw/strings.xml
new file mode 100644
index 0000000..ebb0c02
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Ondoa"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ta/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ta/strings.xml
new file mode 100644
index 0000000..9b175c7
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"மூடும்"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
new file mode 100644
index 0000000..22a6f59
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"విస్మరించు"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-th/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-th/strings.xml
new file mode 100644
index 0000000..6546bfa
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ปิด"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-tl/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-tl/strings.xml
new file mode 100644
index 0000000..9b944de
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"I-dismiss"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-tr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-tr/strings.xml
new file mode 100644
index 0000000..96d49e9
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Kapat"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-uk/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-uk/strings.xml
new file mode 100644
index 0000000..f51b0e7
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Закрити"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ur/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ur/strings.xml
new file mode 100644
index 0000000..ad3fafb
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"برخاست کریں"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-uz/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-uz/strings.xml
new file mode 100644
index 0000000..1e24745
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Yopish"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-vi/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-vi/strings.xml
new file mode 100644
index 0000000..a30cdbf
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Đóng"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-zh-rCN/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..a8f36e4
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"关闭"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-zh-rHK/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..b9ee658
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"關閉"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-zh-rTW/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..b9ee658
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"關閉"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-zu/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-zu/strings.xml
new file mode 100644
index 0000000..80faa17
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Cashisa"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-af/strings.xml b/packages/SettingsLib/FooterPreference/res/values-af/strings.xml
new file mode 100644
index 0000000..c17f3ed
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Kom meer te wete"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-am/strings.xml b/packages/SettingsLib/FooterPreference/res/values-am/strings.xml
new file mode 100644
index 0000000..02e6131
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"የበለጠ ለመረዳት"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ar/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ar/strings.xml
new file mode 100644
index 0000000..1f279a6
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"مزيد من المعلومات"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-as/strings.xml b/packages/SettingsLib/FooterPreference/res/values-as/strings.xml
new file mode 100644
index 0000000..a34b474
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"অধিক জানক"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-az/strings.xml b/packages/SettingsLib/FooterPreference/res/values-az/strings.xml
new file mode 100644
index 0000000..b49036e
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Ətraflı məlumat"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/FooterPreference/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..993ec9a
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Saznajte više"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-be/strings.xml b/packages/SettingsLib/FooterPreference/res/values-be/strings.xml
new file mode 100644
index 0000000..f9d6129
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Даведацца больш"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-bg/strings.xml b/packages/SettingsLib/FooterPreference/res/values-bg/strings.xml
new file mode 100644
index 0000000..605663d
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Научете повече"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml b/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml
new file mode 100644
index 0000000..c58142d
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"আরও জানুন"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-bs/strings.xml b/packages/SettingsLib/FooterPreference/res/values-bs/strings.xml
new file mode 100644
index 0000000..993ec9a
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Saznajte više"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ca/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ca/strings.xml
new file mode 100644
index 0000000..7abf10f
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Més informació"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-cs/strings.xml b/packages/SettingsLib/FooterPreference/res/values-cs/strings.xml
new file mode 100644
index 0000000..decbb68
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Další informace"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-da/strings.xml b/packages/SettingsLib/FooterPreference/res/values-da/strings.xml
new file mode 100644
index 0000000..81d1c7c
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Få flere oplysninger"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-de/strings.xml b/packages/SettingsLib/FooterPreference/res/values-de/strings.xml
new file mode 100644
index 0000000..fe885aa
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Weitere Informationen"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-el/strings.xml b/packages/SettingsLib/FooterPreference/res/values-el/strings.xml
new file mode 100644
index 0000000..5a30833
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Μάθετε περισσότερα"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-en-rAU/strings.xml b/packages/SettingsLib/FooterPreference/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..924d735
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Learn more"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-en-rCA/strings.xml b/packages/SettingsLib/FooterPreference/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..924d735
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Learn more"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-en-rGB/strings.xml b/packages/SettingsLib/FooterPreference/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..924d735
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Learn more"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-en-rIN/strings.xml b/packages/SettingsLib/FooterPreference/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..924d735
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Learn more"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-en-rXC/strings.xml b/packages/SettingsLib/FooterPreference/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..bd12547
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎Learn more‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-es-rUS/strings.xml b/packages/SettingsLib/FooterPreference/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..f31d9ea
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Más información"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-es/strings.xml b/packages/SettingsLib/FooterPreference/res/values-es/strings.xml
new file mode 100644
index 0000000..f31d9ea
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Más información"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-et/strings.xml b/packages/SettingsLib/FooterPreference/res/values-et/strings.xml
new file mode 100644
index 0000000..78b65ed
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Lisateave"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-eu/strings.xml b/packages/SettingsLib/FooterPreference/res/values-eu/strings.xml
new file mode 100644
index 0000000..cf7fa00
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Lortu informazio gehiago"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-fa/strings.xml b/packages/SettingsLib/FooterPreference/res/values-fa/strings.xml
new file mode 100644
index 0000000..464c58e
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"بیشتر بدانید"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-fi/strings.xml b/packages/SettingsLib/FooterPreference/res/values-fi/strings.xml
new file mode 100644
index 0000000..856b962
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Lue lisää"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-fr-rCA/strings.xml b/packages/SettingsLib/FooterPreference/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..6d856ca
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"En savoir plus"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-fr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-fr/strings.xml
new file mode 100644
index 0000000..6d856ca
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"En savoir plus"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-gl/strings.xml b/packages/SettingsLib/FooterPreference/res/values-gl/strings.xml
new file mode 100644
index 0000000..cde57d8
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Máis información"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-gu/strings.xml b/packages/SettingsLib/FooterPreference/res/values-gu/strings.xml
new file mode 100644
index 0000000..54249b8
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"વધુ જાણો"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-hi/strings.xml b/packages/SettingsLib/FooterPreference/res/values-hi/strings.xml
new file mode 100644
index 0000000..95ae240
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ज़्यादा जानें"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-hr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-hr/strings.xml
new file mode 100644
index 0000000..993ec9a
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Saznajte više"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-hu/strings.xml b/packages/SettingsLib/FooterPreference/res/values-hu/strings.xml
new file mode 100644
index 0000000..ae3c948
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"További információ"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-hy/strings.xml b/packages/SettingsLib/FooterPreference/res/values-hy/strings.xml
new file mode 100644
index 0000000..de9137b
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Իմանալ ավելին"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-in/strings.xml b/packages/SettingsLib/FooterPreference/res/values-in/strings.xml
new file mode 100644
index 0000000..4b5cb16
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Pelajari lebih lanjut"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-is/strings.xml b/packages/SettingsLib/FooterPreference/res/values-is/strings.xml
new file mode 100644
index 0000000..111094c
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Nánar"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-it/strings.xml b/packages/SettingsLib/FooterPreference/res/values-it/strings.xml
new file mode 100644
index 0000000..053c80c
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Scopri di più"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-iw/strings.xml b/packages/SettingsLib/FooterPreference/res/values-iw/strings.xml
new file mode 100644
index 0000000..55b0187
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"מידע נוסף"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ja/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ja/strings.xml
new file mode 100644
index 0000000..3312cb4
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"詳細"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ka/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ka/strings.xml
new file mode 100644
index 0000000..67bb223
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"შეიტყვეთ მეტი"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml b/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml
new file mode 100644
index 0000000..db11a76
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Толығырақ"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-km/strings.xml b/packages/SettingsLib/FooterPreference/res/values-km/strings.xml
new file mode 100644
index 0000000..1977dd3
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ស្វែងយល់បន្ថែម"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-kn/strings.xml b/packages/SettingsLib/FooterPreference/res/values-kn/strings.xml
new file mode 100644
index 0000000..47fa3d5
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ko/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ko/strings.xml
new file mode 100644
index 0000000..d8d2200
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"자세히 알아보기"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ky/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ky/strings.xml
new file mode 100644
index 0000000..74c6a49
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Кеңири маалымат"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-lo/strings.xml b/packages/SettingsLib/FooterPreference/res/values-lo/strings.xml
new file mode 100644
index 0000000..2e4124b
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ສຶກສາເພີ່ມເຕີມ"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-lt/strings.xml b/packages/SettingsLib/FooterPreference/res/values-lt/strings.xml
new file mode 100644
index 0000000..2981c66
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Sužinokite daugiau"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-lv/strings.xml b/packages/SettingsLib/FooterPreference/res/values-lv/strings.xml
new file mode 100644
index 0000000..9766305
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Uzzināt vairāk"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-mk/strings.xml b/packages/SettingsLib/FooterPreference/res/values-mk/strings.xml
new file mode 100644
index 0000000..1f734c5
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Дознајте повеќе"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ml/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ml/strings.xml
new file mode 100644
index 0000000..1cd466b
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"കൂടുതലറിയുക"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-mn/strings.xml b/packages/SettingsLib/FooterPreference/res/values-mn/strings.xml
new file mode 100644
index 0000000..8bac1eb
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Нэмэлт мэдээлэл авах"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml
new file mode 100644
index 0000000..4538720
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"अधिक जाणून घ्या"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ms/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ms/strings.xml
new file mode 100644
index 0000000..cd1b17a
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Ketahui lebih lanjut"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-my/strings.xml b/packages/SettingsLib/FooterPreference/res/values-my/strings.xml
new file mode 100644
index 0000000..751a87a
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ပိုမိုလေ့လာရန်"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-nb/strings.xml b/packages/SettingsLib/FooterPreference/res/values-nb/strings.xml
new file mode 100644
index 0000000..08de009
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Finn ut mer"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml
new file mode 100644
index 0000000..ecfec36
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"थप जान्नुहोस्"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-nl/strings.xml b/packages/SettingsLib/FooterPreference/res/values-nl/strings.xml
new file mode 100644
index 0000000..1564081
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Meer informatie"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-or/strings.xml b/packages/SettingsLib/FooterPreference/res/values-or/strings.xml
new file mode 100644
index 0000000..e7924d6
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-pa/strings.xml b/packages/SettingsLib/FooterPreference/res/values-pa/strings.xml
new file mode 100644
index 0000000..1ce2ef2
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ਹੋਰ ਜਾਣੋ"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-pl/strings.xml b/packages/SettingsLib/FooterPreference/res/values-pl/strings.xml
new file mode 100644
index 0000000..5709f3e
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Więcej informacji"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-pt-rBR/strings.xml b/packages/SettingsLib/FooterPreference/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..bc410ab
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Saiba mais"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-pt-rPT/strings.xml b/packages/SettingsLib/FooterPreference/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..bc410ab
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Saiba mais"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-pt/strings.xml b/packages/SettingsLib/FooterPreference/res/values-pt/strings.xml
new file mode 100644
index 0000000..bc410ab
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Saiba mais"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ro/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ro/strings.xml
new file mode 100644
index 0000000..2b50117
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Aflați mai multe"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ru/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ru/strings.xml
new file mode 100644
index 0000000..bedde40
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Подробнее…"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-si/strings.xml b/packages/SettingsLib/FooterPreference/res/values-si/strings.xml
new file mode 100644
index 0000000..1a60601
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"තව දැන ගන්න"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-sk/strings.xml b/packages/SettingsLib/FooterPreference/res/values-sk/strings.xml
new file mode 100644
index 0000000..c1008e5
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Ďalšie informácie"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-sl/strings.xml b/packages/SettingsLib/FooterPreference/res/values-sl/strings.xml
new file mode 100644
index 0000000..79e0a73
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Več o tem"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-sq/strings.xml b/packages/SettingsLib/FooterPreference/res/values-sq/strings.xml
new file mode 100644
index 0000000..0fea476
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Mëso më shumë"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-sr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-sr/strings.xml
new file mode 100644
index 0000000..9a73269
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Сазнајте више"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-sv/strings.xml b/packages/SettingsLib/FooterPreference/res/values-sv/strings.xml
new file mode 100644
index 0000000..a78c3cb
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Läs mer"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-sw/strings.xml b/packages/SettingsLib/FooterPreference/res/values-sw/strings.xml
new file mode 100644
index 0000000..52b1732
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Pata maelezo zaidi"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ta/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ta/strings.xml
new file mode 100644
index 0000000..75fc7c1
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"மேலும் அறிக"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-te/strings.xml b/packages/SettingsLib/FooterPreference/res/values-te/strings.xml
new file mode 100644
index 0000000..6c8d679
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"మరింత తెలుసుకోండి"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-th/strings.xml b/packages/SettingsLib/FooterPreference/res/values-th/strings.xml
new file mode 100644
index 0000000..025a2f0
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ดูข้อมูลเพิ่มเติม"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-tl/strings.xml b/packages/SettingsLib/FooterPreference/res/values-tl/strings.xml
new file mode 100644
index 0000000..4b6f830
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Matuto pa"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-tr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-tr/strings.xml
new file mode 100644
index 0000000..77d15130
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Daha fazla bilgi"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-uk/strings.xml b/packages/SettingsLib/FooterPreference/res/values-uk/strings.xml
new file mode 100644
index 0000000..cec933d
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Докладніше"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ur/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ur/strings.xml
new file mode 100644
index 0000000..1dceea7
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"مزید جانیں"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-uz/strings.xml b/packages/SettingsLib/FooterPreference/res/values-uz/strings.xml
new file mode 100644
index 0000000..5823949
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Batafsil"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-vi/strings.xml b/packages/SettingsLib/FooterPreference/res/values-vi/strings.xml
new file mode 100644
index 0000000..d6c4638
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Tìm hiểu thêm"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-zh-rCN/strings.xml b/packages/SettingsLib/FooterPreference/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..446c8ce
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"了解详情"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-zh-rHK/strings.xml b/packages/SettingsLib/FooterPreference/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..8ab38c6
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"瞭解詳情"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-zh-rTW/strings.xml b/packages/SettingsLib/FooterPreference/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..8ab38c6
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"瞭解詳情"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-zu/strings.xml b/packages/SettingsLib/FooterPreference/res/values-zu/strings.xml
new file mode 100644
index 0000000..b53eb85
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Funda kabanzi"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
index 541a246..281269e 100644
--- a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
@@ -223,7 +223,7 @@
      *
      * @return the uri with added query parameters
      */
-    private static Uri uriWithAddedParameters(Context context, Uri baseUri) {
+    public static Uri uriWithAddedParameters(Context context, Uri baseUri) {
         Uri.Builder builder = baseUri.buildUpon();
 
         // Add in the preferred language
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/LongPressWifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/LongPressWifiEntryPreference.java
deleted file mode 100644
index 503d60c..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/LongPressWifiEntryPreference.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.wifi;
-
-import android.content.Context;
-
-import androidx.fragment.app.Fragment;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.wifitrackerlib.WifiEntry;
-
-/**
- * WifiEntryPreference that can be long pressed.
- */
-public class LongPressWifiEntryPreference extends WifiEntryPreference {
-
-    private final Fragment mFragment;
-
-    public LongPressWifiEntryPreference(Context context, WifiEntry wifiEntry, Fragment fragment) {
-        super(context, wifiEntry);
-        mFragment = fragment;
-    }
-
-    @Override
-    public void onBindViewHolder(final PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        if (mFragment != null) {
-            view.itemView.setOnCreateContextMenuListener(mFragment);
-            view.itemView.setTag(this);
-            view.itemView.setLongClickable(true);
-        }
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
deleted file mode 100644
index 4dd3ff1..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.wifi;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.text.TextUtils;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settingslib.R;
-import com.android.settingslib.Utils;
-import com.android.wifitrackerlib.WifiEntry;
-
-/**
- * Preference to display a WifiEntry in a wifi picker.
- */
-public class WifiEntryPreference extends Preference implements WifiEntry.WifiEntryCallback,
-        View.OnClickListener {
-
-    private static final int[] STATE_SECURED = {
-            R.attr.state_encrypted
-    };
-
-    private static final int[] FRICTION_ATTRS = {
-            R.attr.wifi_friction
-    };
-
-    // These values must be kept within [WifiEntry.WIFI_LEVEL_MIN, WifiEntry.WIFI_LEVEL_MAX]
-    private static final int[] WIFI_CONNECTION_STRENGTH = {
-            R.string.accessibility_no_wifi,
-            R.string.accessibility_wifi_one_bar,
-            R.string.accessibility_wifi_two_bars,
-            R.string.accessibility_wifi_three_bars,
-            R.string.accessibility_wifi_signal_full
-    };
-
-    // StateListDrawable to display secured lock / metered "$" icon
-    @Nullable private final StateListDrawable mFrictionSld;
-    private final IconInjector mIconInjector;
-    private WifiEntry mWifiEntry;
-    private int mLevel = -1;
-    private boolean mShowX; // Shows the Wi-Fi signl icon of Pie+x when it's true.
-    private CharSequence mContentDescription;
-    private OnButtonClickListener mOnButtonClickListener;
-
-    public WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry) {
-        this(context, wifiEntry, new IconInjector(context));
-    }
-
-    @VisibleForTesting
-    WifiEntryPreference(@NonNull Context context, @NonNull WifiEntry wifiEntry,
-            @NonNull IconInjector iconInjector) {
-        super(context);
-
-        setLayoutResource(R.layout.preference_access_point);
-        setWidgetLayoutResource(R.layout.access_point_friction_widget);
-        mFrictionSld = getFrictionStateListDrawable();
-        mWifiEntry = wifiEntry;
-        mWifiEntry.setListener(this);
-        mIconInjector = iconInjector;
-        refresh();
-    }
-
-    public WifiEntry getWifiEntry() {
-        return mWifiEntry;
-    }
-
-    @Override
-    public void onBindViewHolder(final PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        final Drawable drawable = getIcon();
-        if (drawable != null) {
-            drawable.setLevel(mLevel);
-        }
-
-        view.itemView.setContentDescription(mContentDescription);
-
-        // Turn off divider
-        view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE);
-
-        // Enable the icon button when the help string in this WifiEntry is not null.
-        final ImageButton imageButton = (ImageButton) view.findViewById(R.id.icon_button);
-        final ImageView frictionImageView = (ImageView) view.findViewById(
-                R.id.friction_icon);
-        if (mWifiEntry.getHelpUriString() != null
-                && mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
-            final Drawable drawablehelp = getDrawable(R.drawable.ic_help);
-            drawablehelp.setTintList(
-                    Utils.getColorAttr(getContext(), android.R.attr.colorControlNormal));
-            ((ImageView) imageButton).setImageDrawable(drawablehelp);
-            imageButton.setVisibility(View.VISIBLE);
-            imageButton.setOnClickListener(this);
-            imageButton.setContentDescription(
-                    getContext().getText(R.string.help_label));
-
-            if (frictionImageView != null) {
-                frictionImageView.setVisibility(View.GONE);
-            }
-        } else {
-            imageButton.setVisibility(View.GONE);
-
-            if (frictionImageView != null) {
-                frictionImageView.setVisibility(View.VISIBLE);
-                bindFrictionImage(frictionImageView);
-            }
-        }
-    }
-
-    /**
-     * Updates the title and summary; may indirectly call notifyChanged().
-     */
-    public void refresh() {
-        setTitle(mWifiEntry.getTitle());
-        final int level = mWifiEntry.getLevel();
-        final boolean showX = mWifiEntry.shouldShowXLevelIcon();
-        if (level != mLevel || showX != mShowX) {
-            mLevel = level;
-            mShowX = showX;
-            updateIcon(mShowX, mLevel);
-            notifyChanged();
-        }
-
-        setSummary(mWifiEntry.getSummary(false /* concise */));
-        mContentDescription = buildContentDescription();
-    }
-
-    /**
-     * Indicates the state of the WifiEntry has changed and clients may retrieve updates through
-     * the WifiEntry getter methods.
-     */
-    public void onUpdated() {
-        // TODO(b/70983952): Fill this method in
-        refresh();
-    }
-
-    /**
-     * Result of the connect request indicated by the WifiEntry.CONNECT_STATUS constants.
-     */
-    public void onConnectResult(int status) {
-        // TODO(b/70983952): Fill this method in
-    }
-
-    /**
-     * Result of the disconnect request indicated by the WifiEntry.DISCONNECT_STATUS constants.
-     */
-    public void onDisconnectResult(int status) {
-        // TODO(b/70983952): Fill this method in
-    }
-
-    /**
-     * Result of the forget request indicated by the WifiEntry.FORGET_STATUS constants.
-     */
-    public void onForgetResult(int status) {
-        // TODO(b/70983952): Fill this method in
-    }
-
-    /**
-     * Result of the sign-in request indecated by the WifiEntry.SIGNIN_STATUS constants
-     */
-    public void onSignInResult(int status) {
-        // TODO(b/70983952): Fill this method in
-    }
-
-    protected int getIconColorAttr() {
-        final boolean accent = (mWifiEntry.hasInternetAccess()
-                && mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED);
-        return accent ? android.R.attr.colorAccent : android.R.attr.colorControlNormal;
-    }
-
-    private void updateIcon(boolean showX, int level) {
-        if (level == -1) {
-            setIcon(null);
-            return;
-        }
-
-        final Drawable drawable = mIconInjector.getIcon(showX, level);
-        if (drawable != null) {
-            drawable.setTint(Utils.getColorAttrDefaultColor(getContext(), getIconColorAttr()));
-            setIcon(drawable);
-        } else {
-            setIcon(null);
-        }
-    }
-
-    @Nullable
-    private StateListDrawable getFrictionStateListDrawable() {
-        TypedArray frictionSld;
-        try {
-            frictionSld = getContext().getTheme().obtainStyledAttributes(FRICTION_ATTRS);
-        } catch (Resources.NotFoundException e) {
-            // Fallback for platforms that do not need friction icon resources.
-            frictionSld = null;
-        }
-        return frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
-    }
-
-    /**
-     * Binds the friction icon drawable using a StateListDrawable.
-     *
-     * <p>Friction icons will be rebound when notifyChange() is called, and therefore
-     * do not need to be managed in refresh()</p>.
-     */
-    private void bindFrictionImage(ImageView frictionImageView) {
-        if (frictionImageView == null || mFrictionSld == null) {
-            return;
-        }
-        if ((mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE)
-                && (mWifiEntry.getSecurity() != WifiEntry.SECURITY_OWE)) {
-            mFrictionSld.setState(STATE_SECURED);
-        }
-        frictionImageView.setImageDrawable(mFrictionSld.getCurrent());
-    }
-
-    /**
-     * Helper method to generate content description string.
-     */
-    @VisibleForTesting
-    CharSequence buildContentDescription() {
-        final Context context = getContext();
-
-        CharSequence contentDescription = getTitle();
-        final CharSequence summary = getSummary();
-        if (!TextUtils.isEmpty(summary)) {
-            contentDescription = TextUtils.concat(contentDescription, ",", summary);
-        }
-        int level = mWifiEntry.getLevel();
-        if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
-            contentDescription = TextUtils.concat(contentDescription, ",",
-                    context.getString(WIFI_CONNECTION_STRENGTH[level]));
-        }
-        return TextUtils.concat(contentDescription, ",",
-                mWifiEntry.getSecurity() == WifiEntry.SECURITY_NONE
-                        ? context.getString(R.string.accessibility_wifi_security_type_none)
-                        : context.getString(R.string.accessibility_wifi_security_type_secured));
-    }
-
-
-    static class IconInjector {
-        private final Context mContext;
-
-        IconInjector(Context context) {
-            mContext = context;
-        }
-
-        public Drawable getIcon(boolean showX, int level) {
-            return mContext.getDrawable(WifiUtils.getInternetIconResource(level, showX));
-        }
-    }
-
-    /**
-     * Set listeners, who want to listen the button client event.
-     */
-    public void setOnButtonClickListener(OnButtonClickListener listener) {
-        mOnButtonClickListener = listener;
-        notifyChanged();
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (view.getId() == R.id.icon_button) {
-            if (mOnButtonClickListener != null) {
-                mOnButtonClickListener.onButtonClick(this);
-            }
-        }
-    }
-
-    /**
-     * Callback to inform the caller that the icon button is clicked.
-     */
-    public interface OnButtonClickListener {
-
-        /**
-         * Register to listen the button click event.
-         */
-        void onButtonClick(WifiEntryPreference preference);
-    }
-
-    private Drawable getDrawable(@DrawableRes int iconResId) {
-        Drawable buttonIcon = null;
-
-        try {
-            buttonIcon = getContext().getDrawable(iconResId);
-        } catch (Resources.NotFoundException exception) {
-            // Do nothing
-        }
-        return buttonIcon;
-    }
-
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
deleted file mode 100644
index c21830b..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.wifi;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settingslib.R;
-import com.android.wifitrackerlib.WifiEntry;
-
-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.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class WifiEntryPreferenceTest {
-
-    private Context mContext;
-
-    @Mock
-    private WifiEntry mMockWifiEntry;
-    @Mock
-    private WifiEntryPreference.IconInjector mMockIconInjector;
-
-    @Mock
-    private Drawable mMockDrawable0;
-    @Mock
-    private Drawable mMockDrawable1;
-    @Mock
-    private Drawable mMockDrawable2;
-    @Mock
-    private Drawable mMockDrawable3;
-    @Mock
-    private Drawable mMockDrawable4;
-
-    @Mock
-    private Drawable mMockShowXDrawable0;
-    @Mock
-    private Drawable mMockShowXDrawable1;
-    @Mock
-    private Drawable mMockShowXDrawable2;
-    @Mock
-    private Drawable mMockShowXDrawable3;
-    @Mock
-    private Drawable mMockShowXDrawable4;
-
-    private static final String MOCK_TITLE = "title";
-    private static final String MOCK_SUMMARY = "summary";
-    private static final String FAKE_URI_STRING = "fakeuri";
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-
-        MockitoAnnotations.initMocks(this);
-
-        when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE);
-        when(mMockWifiEntry.getSummary(false /* concise */)).thenReturn(MOCK_SUMMARY);
-
-        when(mMockIconInjector.getIcon(false /* showX */, 0)).thenReturn(mMockDrawable0);
-        when(mMockIconInjector.getIcon(false /* showX */, 1)).thenReturn(mMockDrawable1);
-        when(mMockIconInjector.getIcon(false /* showX */, 2)).thenReturn(mMockDrawable2);
-        when(mMockIconInjector.getIcon(false /* showX */, 3)).thenReturn(mMockDrawable3);
-        when(mMockIconInjector.getIcon(false /* showX */, 4)).thenReturn(mMockDrawable4);
-
-        when(mMockIconInjector.getIcon(true /* showX */, 0))
-                .thenReturn(mMockShowXDrawable0);
-        when(mMockIconInjector.getIcon(true /* showX */, 1))
-                .thenReturn(mMockShowXDrawable1);
-        when(mMockIconInjector.getIcon(true /* showX */, 2))
-                .thenReturn(mMockShowXDrawable2);
-        when(mMockIconInjector.getIcon(true /* showX */, 3))
-                .thenReturn(mMockShowXDrawable3);
-        when(mMockIconInjector.getIcon(true /* showX */, 4))
-                .thenReturn(mMockShowXDrawable4);
-    }
-
-    @Test
-    public void constructor_shouldSetWifiEntryTitleAndSummary() {
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-
-        assertThat(pref.getTitle()).isEqualTo(MOCK_TITLE);
-        assertThat(pref.getSummary()).isEqualTo(MOCK_SUMMARY);
-    }
-
-    @Test
-    public void constructor_shouldSetIcon() {
-        when(mMockWifiEntry.getLevel()).thenReturn(0);
-
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-
-        assertThat(pref.getIcon()).isEqualTo(mMockDrawable0);
-    }
-
-    @Test
-    public void titleChanged_refresh_shouldUpdateTitle() {
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-        final String updatedTitle = "updated title";
-        when(mMockWifiEntry.getTitle()).thenReturn(updatedTitle);
-
-        pref.refresh();
-
-        assertThat(pref.getTitle()).isEqualTo(updatedTitle);
-    }
-
-    @Test
-    public void summaryChanged_refresh_shouldUpdateSummary() {
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-        final String updatedSummary = "updated summary";
-        when(mMockWifiEntry.getSummary(false /* concise */)).thenReturn(updatedSummary);
-
-        pref.refresh();
-
-        assertThat(pref.getSummary()).isEqualTo(updatedSummary);
-    }
-
-    @Test
-    public void levelChanged_refresh_shouldUpdateLevelIcon() {
-        final List<Drawable> iconList = new ArrayList<>();
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-
-        when(mMockWifiEntry.getLevel()).thenReturn(0);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(1);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(2);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(3);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(4);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(-1);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-
-        assertThat(iconList).containsExactly(mMockDrawable0, mMockDrawable1,
-                mMockDrawable2, mMockDrawable3, mMockDrawable4, null);
-    }
-
-    @Test
-    public void levelChanged_showXWifiRefresh_shouldUpdateLevelIcon() {
-        final List<Drawable> iconList = new ArrayList<>();
-        when(mMockWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-
-        when(mMockWifiEntry.getLevel()).thenReturn(0);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(1);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(2);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(3);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(4);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-        when(mMockWifiEntry.getLevel()).thenReturn(-1);
-        pref.refresh();
-        iconList.add(pref.getIcon());
-
-        assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1,
-                mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null);
-    }
-
-    @Test
-    public void notNull_whenGetHelpUriString_shouldSetImageButtonVisible() {
-        when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext),
-                false);
-        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
-
-        pref.onBindViewHolder(holder);
-
-        assertThat(view.findViewById(R.id.icon_button).getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void helpButton_whenGetHelpUriStringNotNull_shouldSetCorrectContentDescription() {
-        when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING);
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext),
-                false);
-        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
-
-        pref.onBindViewHolder(holder);
-
-        assertThat(view.findViewById(R.id.icon_button).getContentDescription()).isEqualTo(
-                mContext.getString(R.string.help_label));
-    }
-
-    @Test
-    public void subscriptionEntry_shouldSetImageButtonGone() {
-        when(mMockWifiEntry.isSubscription()).thenReturn(true);
-        final WifiEntryPreference pref =
-                new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector);
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext),
-                false);
-        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
-
-        pref.onBindViewHolder(holder);
-
-        assertThat(view.findViewById(R.id.icon_button).getVisibility()).isEqualTo(View.GONE);
-    }
-}
diff --git a/packages/SettingsProvider/res/values-mcc466/defaults.xml b/packages/SettingsProvider/res/values-mcc466/defaults.xml
new file mode 100644
index 0000000..fdeda88
--- /dev/null
+++ b/packages/SettingsProvider/res/values-mcc466/defaults.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Whether to enable mute when off body by default. -->
+    <bool name="def_wearable_muteWhenOffBodyEnabled">false</bool>
+</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 8e6e251..065fe81 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -214,6 +214,10 @@
     <!-- Default for Settings.System.VIBRATE_WHEN_RINGING -->
     <bool name="def_vibrate_when_ringing">false</bool>
 
+    <!-- Default for Settings.Global.CELL_ON; see PhoneConstants.CELL_ON_FLAG.
+        0: cellular off; 1: cellular on. -->
+    <integer name="def_cell_on">1</integer>
+
     <!-- Default for Settings.Global.APPLY_RAMPING_RINGER -->
     <bool name="def_apply_ramping_ringer">false</bool>
 
@@ -259,4 +263,52 @@
     <!-- Default for Settings.Secure.ONE_HANDED_MODE_ACTIVATED -->
     <bool name="def_one_handed_mode_activated">false</bool>
 
+    <!-- ========================================== -->
+    <!-- Default values for wear specific settings. -->
+
+    <bool name="def_wearable_hotwordDetectionEnabled">false</bool>
+
+    <bool name="def_wearable_smartIlluminateEnabled">true</bool>
+
+    <integer name="def_wearable_offChargerWifiUsageLimitMinutes">120</integer>
+
+    <!-- Default enabled state of accelerometer-based up/down gestures. -->
+    <bool name="def_wearable_upDownGesturesEnabled">false</bool>
+
+    <!-- Whether to enable mute when off body by default. -->
+    <bool name="def_wearable_muteWhenOffBodyEnabled">true</bool>
+
+    <!-- Whether to use an alternate launcher if available. -->
+    <bool name="def_wearable_alternateLauncherEnabled">true</bool>
+
+    <!-- If a square screen, how rounded the corners are. Same as CSS border-radius property. -->
+    <integer name="def_wearable_squareScreenCornerRoundness">0</integer>
+
+    <!-- Side button present -->
+    <bool name="def_wearable_sideButtonPresent">true</bool>
+
+    <!-- Android wear version. This value is a string due to no long type in resources -->
+    <string name="def_wearable_androidWearVersion" translatable="false">2</string>
+
+    <!-- This value is the decimal representation of the capabilities bitmask as defined below:
+        0000001 - WIFI
+        0000010 - Accounts
+        0000100 - Phone
+        0001000 - Cell
+        0010000 - Companion Legacy Calling
+        0100000 - Speaker
+        1000000 - Setup Protocomm Channel
+
+        Note: These must match the positions in
+            com.google.android.clockwork.common.system.WearSystemConstants  -->
+    <string name="def_wearable_systemCapabilities" translatable="false">3</string>
+
+    <!-- This value is used for the default system capabilities used on LE device. -->
+    <string name="def_wearable_leSystemCapabilities" translatable="false">1</string>
+
+    <!-- Brightness levels, on a 0-255 scale -->
+    <string name="def_wearable_brightnessLevels" translatable="false">255,204,153,102,51</string>
+
+    <!-- Whether to allow mobile signal detector by default. -->
+    <bool name="def_wearable_mobileSignalDetectorAllowed">true</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index eb81961..b84a9cd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -40,6 +40,9 @@
     public static final String[] SETTINGS_TO_BACKUP = {
         Settings.Global.APPLY_RAMPING_RINGER,
         Settings.Global.BUGREPORT_IN_POWER_MENU,
+        Settings.Global.CLOCKWORK_SYSUI_PACKAGE_NAME,
+        Settings.Global.CLOCKWORK_SYSUI_MAIN_ACTIVITY_NAME,
+        Settings.Global.CLOCKWORK_HOME_READY,
         Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
         Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
         Settings.Global.AUTO_TIME,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 5220a04..9f10734 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -113,6 +113,9 @@
         VALIDATORS.put(
                 Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, PERCENTAGE_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.BLUETOOTH_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.CLOCKWORK_SYSUI_MAIN_ACTIVITY_NAME, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.CLOCKWORK_SYSUI_PACKAGE_NAME, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.CLOCKWORK_HOME_READY, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.PRIVATE_DNS_MODE, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.PRIVATE_DNS_SPECIFIER, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.SOFT_AP_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
@@ -140,6 +143,118 @@
                         /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
         VALIDATORS.put(Global.DISABLE_WINDOW_BLURS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.DEVICE_CONFIG_SYNC_DISABLED, BOOLEAN_VALIDATOR);
+
+        VALIDATORS.put(Global.Wearable.HAS_PAY_TOKENS, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.HOTWORD_DETECTION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.SMART_REPLIES_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.RETAIL_MODE,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.RETAIL_MODE_CONSUMER),
+                            String.valueOf(Global.Wearable.RETAIL_MODE_RETAIL)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.PLAY_STORE_AVAILABILITY,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.PLAY_STORE_AVAILABLE),
+                            String.valueOf(Global.Wearable.PLAY_STORE_UNAVAILABLE),
+                            String.valueOf(Global.Wearable.PLAY_STORE_AVAILABILITY_UNKNOWN)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.BUG_REPORT,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.BUG_REPORT_ENABLED),
+                            String.valueOf(Global.Wearable.BUG_REPORT_DISABLED)
+                        }));
+        VALIDATORS.put(Global.Wearable.SMART_ILLUMINATE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.CLOCKWORK_AUTO_TIME,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.SYNC_TIME_FROM_PHONE),
+                            String.valueOf(Global.Wearable.SYNC_TIME_FROM_NETWORK),
+                            String.valueOf(Global.Wearable.AUTO_TIME_OFF),
+                            String.valueOf(Global.Wearable.INVALID_AUTO_TIME_STATE)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.SYNC_TIME_ZONE_FROM_PHONE),
+                            String.valueOf(Global.Wearable.SYNC_TIME_ZONE_FROM_NETWORK),
+                            String.valueOf(Global.Wearable.AUTO_TIME_ZONE_OFF),
+                            String.valueOf(Global.Wearable.INVALID_AUTO_TIME_ZONE_STATE)
+                        }));
+        VALIDATORS.put(Global.Wearable.CLOCKWORK_24HR_TIME, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.AUTO_WIFI, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.WIFI_POWER_SAVE, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS,
+                ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.UPDOWN_GESTURES_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.SETUP_SKIPPED,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.SETUP_SKIPPED_YES),
+                            String.valueOf(Global.Wearable.SETUP_SKIPPED_NO),
+                            String.valueOf(Global.Wearable.SETUP_SKIPPED_UNKNOWN)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.LAST_CALL_FORWARD_ACTION,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.CALL_FORWARD_ACTION_ON),
+                            String.valueOf(Global.Wearable.CALL_FORWARD_ACTION_OFF),
+                            String.valueOf(Global.Wearable.CALL_FORWARD_NO_LAST_ACTION)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.STEM_1_TYPE,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.STEM_TYPE_UNKNOWN),
+                            String.valueOf(Global.Wearable.STEM_TYPE_APP_LAUNCH),
+                            String.valueOf(Global.Wearable.STEM_TYPE_CONTACT_LAUNCH)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.STEM_2_TYPE,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.STEM_TYPE_UNKNOWN),
+                            String.valueOf(Global.Wearable.STEM_TYPE_APP_LAUNCH),
+                            String.valueOf(Global.Wearable.STEM_TYPE_CONTACT_LAUNCH)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.STEM_3_TYPE,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.STEM_TYPE_UNKNOWN),
+                            String.valueOf(Global.Wearable.STEM_TYPE_APP_LAUNCH),
+                            String.valueOf(Global.Wearable.STEM_TYPE_CONTACT_LAUNCH)
+                        }));
+        VALIDATORS.put(Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.ALTERNATE_LAUNCHER_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.CORNER_ROUNDNESS, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.SIDE_BUTTON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.BUTTON_SET, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.ANDROID_WEAR_VERSION, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.SYSTEM_CAPABILITIES, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.SYSTEM_EDITION, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.WEAR_PLATFORM_MR_NUMBER, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.BOTTOM_OFFSET, ANY_INTEGER_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.DISPLAY_SHAPE,
+                new DiscreteValueValidator(
+                        new String[] {
+                            String.valueOf(Global.Wearable.DISPLAY_SHAPE_ROUND),
+                            String.valueOf(Global.Wearable.DISPLAY_SHAPE_SQUARE)
+                        }));
+        VALIDATORS.put(Global.Wearable.MOBILE_SIGNAL_DETECTOR, 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 268603f..cdf274f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2467,6 +2467,9 @@
             loadBooleanSetting(stmt, Settings.Global.BLUETOOTH_ON,
                     R.bool.def_bluetooth_on);
 
+            loadIntegerSetting(stmt, Settings.Global.CELL_ON,
+                    R.integer.def_cell_on);
+
             // Enable or disable Cell Broadcast SMS
             loadSetting(stmt, Settings.Global.CDMA_CELL_BROADCAST_SMS,
                     RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 00fd19c..f83ebaa 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -33,6 +33,7 @@
 import android.os.ShellCommand;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.provider.Settings.Config.SyncDisabledMode;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -69,7 +70,7 @@
             LIST,
             RESET,
             SET_SYNC_DISABLED_FOR_TESTS,
-            IS_SYNC_DISABLED_FOR_TESTS,
+            GET_SYNC_DISABLED_FOR_TESTS,
         }
 
         MyShellCommand(SettingsProvider provider) {
@@ -103,8 +104,8 @@
                 verb = CommandVerb.RESET;
             } else if ("set_sync_disabled_for_tests".equalsIgnoreCase(cmd)) {
                 verb = CommandVerb.SET_SYNC_DISABLED_FOR_TESTS;
-            } else if ("is_sync_disabled_for_tests".equalsIgnoreCase(cmd)) {
-                verb = CommandVerb.IS_SYNC_DISABLED_FOR_TESTS;
+            } else if ("get_sync_disabled_for_tests".equalsIgnoreCase(cmd)) {
+                verb = CommandVerb.GET_SYNC_DISABLED_FOR_TESTS;
                 if (peekNextArg() != null) {
                     perr.println("Bad arguments");
                     return -1;
@@ -117,7 +118,7 @@
             }
 
             // Parse args for those commands that have them.
-            int disableSyncMode = -1;
+            int syncDisabledModeArg = -1;
             int resetMode = -1;
             boolean makeDefault = false;
             String namespace = null;
@@ -154,15 +155,10 @@
                         }
                     }
                 } else if (verb == CommandVerb.SET_SYNC_DISABLED_FOR_TESTS) {
-                    if (disableSyncMode == -1) {
-                        // DISABLE_SYNC_FOR_TESTS 1st arg (required)
-                        if ("none".equalsIgnoreCase(arg)) {
-                            disableSyncMode = SYNC_DISABLED_MODE_NONE;
-                        } else if ("persistent".equalsIgnoreCase(arg)) {
-                            disableSyncMode = SYNC_DISABLED_MODE_PERSISTENT;
-                        } else if ("until_reboot".equalsIgnoreCase(arg)) {
-                            disableSyncMode = SYNC_DISABLED_MODE_UNTIL_REBOOT;
-                        } else {
+                    if (syncDisabledModeArg == -1) {
+                        // SET_SYNC_DISABLED_FOR_TESTS 1st arg (required)
+                        syncDisabledModeArg = parseSyncDisabledMode(arg);
+                        if (syncDisabledModeArg == -1) {
                             // invalid
                             perr.println("Invalid sync disabled mode: " + arg);
                             return -1;
@@ -252,10 +248,16 @@
                     DeviceConfig.resetToDefaults(resetMode, namespace);
                     break;
                 case SET_SYNC_DISABLED_FOR_TESTS:
-                    DeviceConfig.setSyncDisabled(disableSyncMode);
+                    DeviceConfig.setSyncDisabledMode(syncDisabledModeArg);
                     break;
-                case IS_SYNC_DISABLED_FOR_TESTS:
-                    pout.println(DeviceConfig.isSyncDisabled());
+                case GET_SYNC_DISABLED_FOR_TESTS:
+                    int syncDisabledModeInt = DeviceConfig.getSyncDisabledMode();
+                    String syncDisabledModeString = formatSyncDisabledMode(syncDisabledModeInt);
+                    if (syncDisabledModeString == null) {
+                        perr.println("Unknown mode: " + syncDisabledModeInt);
+                        return -1;
+                    }
+                    pout.println(syncDisabledModeString);
                     break;
                 default:
                     perr.println("Unspecified command");
@@ -295,8 +297,9 @@
                     + " syncing.");
             pw.println("        persistent: Sync is disabled, this state will survive a reboot.");
             pw.println("        until_reboot: Sync is disabled until the next reboot.");
-            pw.println("  is_sync_disabled_for_tests");
-            pw.println("      Prints 'true' if sync is disabled, 'false' otherwise.");
+            pw.println("  get_sync_disabled_for_tests");
+            pw.println("      Prints one of the SYNC_DISABLED_MODE values, see"
+                    + " set_sync_disabled_for_tests");
         }
 
         private boolean delete(IContentProvider provider, String namespace, String key) {
@@ -358,4 +361,31 @@
             }
         }
     }
+
+    private static @SyncDisabledMode int parseSyncDisabledMode(String arg) {
+        int syncDisabledMode;
+        if ("none".equalsIgnoreCase(arg)) {
+            syncDisabledMode = SYNC_DISABLED_MODE_NONE;
+        } else if ("persistent".equalsIgnoreCase(arg)) {
+            syncDisabledMode = SYNC_DISABLED_MODE_PERSISTENT;
+        } else if ("until_reboot".equalsIgnoreCase(arg)) {
+            syncDisabledMode = SYNC_DISABLED_MODE_UNTIL_REBOOT;
+        } else {
+            syncDisabledMode = -1;
+        }
+        return syncDisabledMode;
+    }
+
+    private static String formatSyncDisabledMode(@SyncDisabledMode int syncDisabledMode) {
+        switch (syncDisabledMode) {
+            case SYNC_DISABLED_MODE_NONE:
+                return "none";
+            case SYNC_DISABLED_MODE_PERSISTENT:
+                return "persistent";
+            case SYNC_DISABLED_MODE_UNTIL_REBOOT:
+                return "until_reboot";
+            default:
+                return null;
+        }
+    }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e5eecb2..86b3bab1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -763,9 +763,6 @@
                 Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
                 GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
         dumpSetting(s, p,
-                Settings.Global.ANGLE_ALLOWLIST,
-                GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST);
-        dumpSetting(s, p,
                 Settings.Global.ANGLE_EGL_FEATURES,
                 GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index dd9a6ee..ce98d4c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -85,6 +85,7 @@
 import android.os.RemoteException;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.DeviceConfig;
@@ -136,7 +137,6 @@
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
-
 /**
  * <p>
  * This class is a content provider that publishes the system settings.
@@ -471,16 +471,16 @@
                 return result;
             }
 
-            case Settings.CALL_METHOD_SET_SYNC_DISABLED_CONFIG: {
+            case Settings.CALL_METHOD_SET_SYNC_DISABLED_MODE_CONFIG: {
                 final int mode = getSyncDisabledMode(args);
-                setSyncDisabledConfig(mode);
+                setSyncDisabledModeConfig(mode);
                 break;
             }
 
-            case Settings.CALL_METHOD_IS_SYNC_DISABLED_CONFIG: {
+            case Settings.CALL_METHOD_GET_SYNC_DISABLED_MODE_CONFIG: {
                 Bundle result = new Bundle();
-                result.putBoolean(Settings.KEY_CONFIG_IS_SYNC_DISABLED_RETURN,
-                        isSyncDisabledConfig());
+                result.putInt(Settings.KEY_CONFIG_GET_SYNC_DISABLED_MODE_RETURN,
+                        getSyncDisabledModeConfig());
                 return result;
             }
 
@@ -1147,7 +1147,7 @@
         enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
 
         synchronized (mLock) {
-            if (isSyncDisabledConfigLocked()) {
+            if (getSyncDisabledModeConfigLocked() != SYNC_DISABLED_MODE_NONE) {
                 return SET_ALL_RESULT_DISABLED;
             }
             final int key = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
@@ -1157,32 +1157,32 @@
         }
     }
 
-    private void setSyncDisabledConfig(@SyncDisabledMode int syncDisabledMode) {
+    private void setSyncDisabledModeConfig(@SyncDisabledMode int syncDisabledMode) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "setSyncDisabledConfig(" + syncDisabledMode + ")");
+            Slog.v(LOG_TAG, "setSyncDisabledModeConfig(" + syncDisabledMode + ")");
         }
 
         enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
 
         synchronized (mLock) {
-            setSyncDisabledConfigLocked(syncDisabledMode);
+            setSyncDisabledModeConfigLocked(syncDisabledMode);
         }
     }
 
-    private boolean isSyncDisabledConfig() {
+    private int getSyncDisabledModeConfig() {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "isSyncDisabledConfig");
+            Slog.v(LOG_TAG, "getSyncDisabledModeConfig");
         }
 
         enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
 
         synchronized (mLock) {
-            return isSyncDisabledConfigLocked();
+            return getSyncDisabledModeConfigLocked();
         }
     }
 
     @GuardedBy("mLock")
-    private void setSyncDisabledConfigLocked(@SyncDisabledMode int syncDisabledMode) {
+    private void setSyncDisabledModeConfigLocked(@SyncDisabledMode int syncDisabledMode) {
         boolean persistentValue;
         boolean inMemoryValue;
         if (syncDisabledMode == SYNC_DISABLED_MODE_NONE) {
@@ -1214,13 +1214,13 @@
     }
 
     @GuardedBy("mLock")
-    private boolean isSyncDisabledConfigLocked() {
+    private int getSyncDisabledModeConfigLocked() {
         // Check the values used for both SYNC_DISABLED_MODE_PERSISTENT and
         // SYNC_DISABLED_MODE_UNTIL_REBOOT.
 
         // The SYNC_DISABLED_MODE_UNTIL_REBOOT value is cheap to check first.
         if (mSyncConfigDisabledUntilReboot) {
-            return true;
+            return SYNC_DISABLED_MODE_UNTIL_REBOOT;
         }
 
         // Now check the global setting used to implement SYNC_DISABLED_MODE_PERSISTENT.
@@ -1230,10 +1230,12 @@
                     SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM,
                     Global.DEVICE_CONFIG_SYNC_DISABLED);
             if (settingLocked == null) {
-                return false;
+                return SYNC_DISABLED_MODE_NONE;
             }
             String settingValue = settingLocked.getValue();
-            return settingValue != null && !"0".equals(settingValue);
+            boolean isSyncDisabledPersistent = settingValue != null && !"0".equals(settingValue);
+            return isSyncDisabledPersistent
+                    ? SYNC_DISABLED_MODE_PERSISTENT : SYNC_DISABLED_MODE_NONE;
         } finally {
             restoreCallingIdentity(callingIdentity);
         }
@@ -3576,7 +3578,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 203;
+            private static final int SETTINGS_VERSION = 204;
 
             private final int mUserId;
 
@@ -5180,6 +5182,137 @@
                     currentVersion = 203;
                 }
 
+                if (currentVersion == 203) {
+                        // Version 203: initialize entries migrated from wear settings provide.
+                        initGlobalSettingsDefaultValForWearLocked(Global.Wearable.HAS_PAY_TOKENS,
+                                false);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN, 6);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.HOTWORD_DETECTION_ENABLED,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(R.bool.def_wearable_hotwordDetectionEnabled));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.SMART_REPLIES_ENABLED, false);
+                        Setting locationMode = getSecureSettingsLocked(userId)
+                                                        .getSettingLocked(Secure.LOCATION_MODE);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
+                                !locationMode.isNull()
+                                        && !Integer.toString(Secure.LOCATION_MODE_OFF)
+                                                .equals(locationMode.getValue()));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.RETAIL_MODE, Global.Wearable.RETAIL_MODE_CONSUMER);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.PLAY_STORE_AVAILABILITY,
+                                Global.Wearable.PLAY_STORE_AVAILABILITY_UNKNOWN);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.BUG_REPORT,
+                                "user".equals(Build.TYPE) // is user build?
+                                        ? Global.Wearable.BUG_REPORT_DISABLED
+                                        : Global.Wearable.BUG_REPORT_ENABLED);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.SMART_ILLUMINATE_ENABLED,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(R.bool.def_wearable_smartIlluminateEnabled));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.CLOCKWORK_AUTO_TIME,
+                                Global.Wearable.SYNC_TIME_FROM_PHONE);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
+                                Global.Wearable.SYNC_TIME_ZONE_FROM_PHONE);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.CLOCKWORK_24HR_TIME, false);
+                        initGlobalSettingsDefaultValForWearLocked(Global.Wearable.AUTO_WIFI, true);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.WIFI_POWER_SAVE,
+                                getContext()
+                                        .getResources()
+                                        .getInteger(
+                                                R.integer
+                                                    .def_wearable_offChargerWifiUsageLimitMinutes));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS, 0L);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.UPDOWN_GESTURES_ENABLED,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(R.bool.def_wearable_upDownGesturesEnabled));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.SETUP_SKIPPED,
+                                Global.Wearable.SETUP_SKIPPED_UNKNOWN);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.LAST_CALL_FORWARD_ACTION,
+                                Global.Wearable.CALL_FORWARD_NO_LAST_ACTION);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(R.bool.def_wearable_muteWhenOffBodyEnabled));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.WEAR_OS_VERSION_STRING, "");
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.ALTERNATE_LAUNCHER_ENABLED,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(R.bool.def_wearable_alternateLauncherEnabled));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.CORNER_ROUNDNESS,
+                                getContext()
+                                        .getResources()
+                                        .getInteger(
+                                                R.integer
+                                                        .def_wearable_squareScreenCornerRoundness));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.BUTTON_SET, false);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.SIDE_BUTTON,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(R.bool.def_wearable_sideButtonPresent));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.ANDROID_WEAR_VERSION,
+                                Long.parseLong(
+                                        getContext()
+                                                .getResources()
+                                                .getString(
+                                                        R.string.def_wearable_androidWearVersion)));
+                        final int editionGlobal = 1;
+                        final int editionLocal = 2;
+                        boolean isLe =
+                                getContext().getPackageManager().hasSystemFeature("cn.google");
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.SYSTEM_EDITION,
+                                isLe ? editionLocal : editionGlobal);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.SYSTEM_CAPABILITIES,
+                                getWearSystemCapabilities(isLe));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Global.Wearable.WEAR_PLATFORM_MR_NUMBER,
+                                SystemProperties.getInt("ro.cw_build.platform_mr", 0));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Settings.Global.Wearable.BOTTOM_OFFSET, 0);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Settings.Global.Wearable.DISPLAY_SHAPE,
+                                Settings.Global.Wearable.DISPLAY_SHAPE_SQUARE);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Settings.Global.Wearable.SCREEN_BRIGHTNESS_LEVEL,
+                                getContext()
+                                        .getResources()
+                                        .getString(R.string.def_wearable_brightnessLevels));
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR,
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(
+                                                R.bool.def_wearable_mobileSignalDetectorAllowed));
+
+                        // TODO(b/164398026): add necessary initialization logic for all entries.
+                        currentVersion = 204;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
@@ -5196,6 +5329,58 @@
                 // Return the current version.
                 return currentVersion;
             }
+
+            private void initGlobalSettingsDefaultValForWearLocked(String key, boolean val) {
+                initGlobalSettingsDefaultValForWearLocked(key, val ? "1" : "0");
+            }
+
+            private void initGlobalSettingsDefaultValForWearLocked(String key, int val) {
+                initGlobalSettingsDefaultValForWearLocked(key, String.valueOf(val));
+            }
+
+            private void initGlobalSettingsDefaultValForWearLocked(String key, long val) {
+                initGlobalSettingsDefaultValForWearLocked(key, String.valueOf(val));
+            }
+
+            private void initGlobalSettingsDefaultValForWearLocked(String key, String val) {
+                final SettingsState globalSettings = getGlobalSettingsLocked();
+                Setting currentSetting = globalSettings.getSettingLocked(key);
+                if (currentSetting.isNull()) {
+                    globalSettings.insertSettingOverrideableByRestoreLocked(
+                            key,
+                            val,
+                            null /* tag */,
+                            true /* makeDefault */,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                }
+            }
+
+            private long getWearSystemCapabilities(boolean isLe) {
+                // Capability constants are imported from
+                // com.google.android.clockwork.common.system.WearableConstants.
+                final int capabilityCompanionLegacyCalling = 5;
+                final int capabilitySpeaker = 6;
+                final int capabilitySetupProtocommChannel = 7;
+                long capabilities =
+                        Long.parseLong(
+                                getContext().getResources()
+                                .getString(
+                                        isLe ? R.string.def_wearable_leSystemCapabilities
+                                                : R.string.def_wearable_systemCapabilities));
+                PackageManager pm = getContext().getPackageManager();
+                if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+                    capabilities |= getBitMask(capabilityCompanionLegacyCalling);
+                }
+                if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
+                    capabilities |= getBitMask(capabilitySpeaker);
+                }
+                capabilities |= getBitMask(capabilitySetupProtocommChannel);
+                return capabilities;
+            }
+
+            private long getBitMask(int capability) {
+                return 1 << (capability - 1);
+            }
         }
 
         /**
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index f04acd0..1ff5950 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -33,6 +33,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.providers.settings.SettingsOperationProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -47,6 +48,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
 
 import libcore.io.IoUtils;
@@ -806,7 +808,14 @@
 
                 final int settingCount = settings.size();
                 for (int i = 0; i < settingCount; i++) {
+
                     Setting setting = settings.valueAt(i);
+                    if (setting.isTransient()) {
+                        if (DEBUG_PERSISTENCE) {
+                            Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName());
+                        }
+                        continue;
+                    }
 
                     if (writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
                             setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
@@ -1302,6 +1311,14 @@
                     /* resetToDefault */ true);
         }
 
+        public boolean isTransient() {
+            switch (getTypeFromKey(getKey())) {
+                case SETTINGS_TYPE_GLOBAL:
+                    return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName());
+            }
+            return false;
+        }
+
         public boolean update(String value, boolean setDefault, String packageName, String tag,
                 boolean forceNonSystemPackage, boolean overrideableByRestore) {
             return update(value, setDefault, packageName, tag, forceNonSystemPackage,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3297937..a6e0d00 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -509,7 +509,6 @@
                     Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
-                    Settings.Global.ANGLE_ALLOWLIST,
                     Settings.Global.ANGLE_EGL_FEATURES,
                     Settings.Global.UPDATABLE_DRIVER_ALL_APPS,
                     Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS,
@@ -593,7 +592,50 @@
                     Settings.Global.CACHED_APPS_FREEZER_ENABLED,
                     Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
                     Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
-                    Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT);
+                    Settings.Global.ADVANCED_BATTERY_USAGE_AMOUNT,
+                    Settings.Global.Wearable.HAS_PAY_TOKENS,
+                    Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
+                    Settings.Global.Wearable.HOTWORD_DETECTION_ENABLED,
+                    Settings.Global.Wearable.SMART_REPLIES_ENABLED,
+                    Settings.Global.Wearable.DEFAULT_VIBRATION,
+                    Settings.Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
+                    Settings.Global.Wearable.RETAIL_MODE,
+                    Settings.Global.Wearable.PLAY_STORE_AVAILABILITY,
+                    Settings.Global.Wearable.BUG_REPORT,
+                    Settings.Global.Wearable.SMART_ILLUMINATE_ENABLED,
+                    Settings.Global.Wearable.CLOCKWORK_AUTO_TIME,
+                    Settings.Global.Wearable.CLOCKWORK_AUTO_TIME_ZONE,
+                    Settings.Global.Wearable.CLOCKWORK_24HR_TIME,
+                    Settings.Global.Wearable.AUTO_WIFI,
+                    Settings.Global.Wearable.WIFI_POWER_SAVE,
+                    Settings.Global.Wearable.ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS,
+                    Settings.Global.Wearable.UPDOWN_GESTURES_ENABLED,
+                    Settings.Global.Wearable.SETUP_SKIPPED,
+                    Settings.Global.Wearable.LAST_CALL_FORWARD_ACTION,
+                    Settings.Global.Wearable.STEM_1_TYPE,
+                    Settings.Global.Wearable.STEM_1_DATA,
+                    Settings.Global.Wearable.STEM_1_DEFAULT_DATA,
+                    Settings.Global.Wearable.STEM_2_TYPE,
+                    Settings.Global.Wearable.STEM_2_DATA,
+                    Settings.Global.Wearable.STEM_2_DEFAULT_DATA,
+                    Settings.Global.Wearable.STEM_3_TYPE,
+                    Settings.Global.Wearable.STEM_3_DATA,
+                    Settings.Global.Wearable.STEM_3_DEFAULT_DATA,
+                    Settings.Global.Wearable.MUTE_WHEN_OFF_BODY_ENABLED,
+                    Settings.Global.Wearable.WEAR_OS_VERSION_STRING,
+                    Settings.Global.Wearable.ALTERNATE_LAUNCHER_ENABLED,
+                    Settings.Global.Wearable.CORNER_ROUNDNESS,
+                    Settings.Global.Wearable.BUTTON_SET,
+                    Settings.Global.Wearable.SIDE_BUTTON,
+                    Settings.Global.Wearable.ANDROID_WEAR_VERSION,
+                    Settings.Global.Wearable.SYSTEM_CAPABILITIES,
+                    Settings.Global.Wearable.SYSTEM_EDITION,
+                    Settings.Global.Wearable.WEAR_PLATFORM_MR_NUMBER,
+                    Settings.Global.Wearable.COMPANION_BT_ADDRESS_DUAL,
+                    Settings.Global.Wearable.DISPLAY_SHAPE,
+                    Settings.Global.Wearable.BOTTOM_OFFSET,
+                    Settings.Global.Wearable.SCREEN_BRIGHTNESS_LEVEL,
+                    Settings.Global.Wearable.MOBILE_SIGNAL_DETECTOR);
 
     private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
              newHashSet(
@@ -763,8 +805,10 @@
 
     @Test
     public void globalSettingsBackedUpOrDenied() {
+        Set<String> candidateSettings = getCandidateSettings(Settings.Global.class);
+        candidateSettings.addAll(getCandidateSettings(Settings.Global.Wearable.class));
         checkSettingsBackedUpOrDenied(
-                getCandidateSettings(Settings.Global.class),
+                candidateSettings,
                 newHashSet(GlobalSettings.SETTINGS_TO_BACKUP),
                 BACKUP_DENY_LIST_GLOBAL_SETTINGS);
     }
@@ -792,8 +836,7 @@
                 .that(intersect(settingsToBackup, denylist)).isEmpty();
     }
 
-    private static Set<String> getCandidateSettings(
-            Class<? extends Settings.NameValueTable> clazz) {
+    private static Set<String> getCandidateSettings(Class<?> clazz) {
         HashSet<String> result = new HashSet<String>();
         for (Field field : clazz.getDeclaredFields()) {
             if (looksLikeValidSetting(field)) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c7b50c2..bc1d420 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -104,7 +104,6 @@
     <uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
     <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
     <uses-permission android:name="android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE" />
     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
index 504e18a..56b940c 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
@@ -256,6 +256,14 @@
         }
 
         setupAlert();
+
+        ListView listView = mAlert.getListView();
+        if (listView != null) {
+            // List view needs to gain focus in order for RSB to work.
+            if (!listView.requestFocus()) {
+                Log.e(TAG, "Unable to gain focus! RSB may not work properly.");
+            }
+        }
     }
     @Override
     public void onSaveInstanceState(Bundle outState) {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b357a94..1d48ae6 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -63,6 +63,7 @@
         "res",
     ],
     static_libs: [
+        "WifiTrackerLib",
         "WindowManager-Shell",
         "SystemUIAnimationLib",
         "SystemUIPluginLib",
@@ -143,6 +144,7 @@
         "src/**/I*.aidl",
     ],
     static_libs: [
+        "WifiTrackerLib",
         "SystemUIAnimationLib",
         "SystemUIPluginLib",
         "SystemUISharedLib",
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 835471d..1cf14f2 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -1,5 +1,7 @@
 set noparent
 
+# Bug component: 78010
+
 dsandler@android.com
 
 aaliomer@google.com
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 0d18b8d..24bffa1 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -53,8 +53,9 @@
 
   // Curious where your @Scenario tests will run?
   //
-  // @Ignore or @FlakyTest: nowhere
-  // @Staging: in staged-postsubmit, but not postsubmit or presubmit
+  // @Ignore: nowhere
+  // @Staging or @FlakyTest: in staged-postsubmit, but not postsubmit or
+  // 	presubmit
   // @Postsubmit: in postsubmit and staged-postsubmit, but not presubmit
   // none of the above: in presubmit, postsubmit, and staged-postsubmit
   //
@@ -98,9 +99,6 @@
         },
         {
             "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-            "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     }
diff --git a/packages/SystemUI/res/layout/global_actions_change_panel.xml b/packages/SystemUI/res/layout/global_actions_change_panel.xml
deleted file mode 100644
index bc9c203..0000000
--- a/packages/SystemUI/res/layout/global_actions_change_panel.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2021 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content">
-    <TextView
-        android:id="@+id/global_actions_change_message"
-        android:layout_width="wrap_content"
-        android:visibility="gone"
-        android:layout_height="wrap_content"
-        android:text="@string/global_actions_change_description" />
-    <ImageView
-        android:id="@+id/global_actions_change_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_grid_lite.xml b/packages/SystemUI/res/layout/global_actions_grid_lite.xml
index 5588fd3..2430eec 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_lite.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_lite.xml
@@ -13,12 +13,13 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<androidx.constraintlayout.widget.ConstraintLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/global_actions_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:orientation="vertical"
     android:gravity="center"
     android:layout_gravity="center">
   <com.android.systemui.globalactions.GlobalActionsLayoutLite
@@ -28,11 +29,8 @@
       android:orientation="vertical"
       android:clipChildren="false"
       android:clipToPadding="false"
-      app:layout_constraintBottom_toBottomOf="parent"
-      app:layout_constraintTop_toTopOf="parent"
-      app:layout_constraintStart_toStartOf="parent"
-      app:layout_constraintEnd_toEndOf="parent"
-      android:layout_weight="1">
+      android:background="@drawable/global_actions_lite_background"
+      android:padding="@dimen/global_actions_lite_padding">
     <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -40,8 +38,6 @@
         android:gravity="center"
         android:translationZ="@dimen/global_actions_translate"
         android:orientation="horizontal"
-        android:background="@drawable/global_actions_lite_background"
-        android:padding="@dimen/global_actions_lite_padding"
         android:layoutDirection="ltr">
       <androidx.constraintlayout.helper.widget.Flow
           android:id="@+id/list_flow"
@@ -57,4 +53,4 @@
           app:flow_horizontalStyle="packed"/>
     </androidx.constraintlayout.widget.ConstraintLayout>
   </com.android.systemui.globalactions.GlobalActionsLayoutLite>
-</androidx.constraintlayout.widget.ConstraintLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ab91e78..89e841e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Gespreklegstukke"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tik op \'n gesprek om dit by jou tuisskerm te voeg"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Kom kyk weer nadat jy \'n paar boodskappe gekry het"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioriteitgesprekke"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Onlangse gesprekke"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Sien onlangse boodskappe, gemiste oproepe en statusopdaterings"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Gesprek"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Onderbreek deur Moenie Steur nie"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> het \'n boodskap gestuur"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> het \'n prent gestuur"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kon nie jou batterymeter lees nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 823f9a1..5d94dba 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"ውይይት ይክፈቱ"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"የውይይት ምግብሮች"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"በመነሻ ማያ ገጽዎ ላይ ለማከል አንድ ውይይት መታ ያድርጉ"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"አንዳንድ መልዕክቶች ከደረሰዎት በኋላ እዚህ ተመልሰው ይፈትሹ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"የቅድሚያ ውይይቶች"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"የቅርብ ጊዜ ውይይቶች"</string>
     <string name="okay" msgid="6490552955618608554">"እሺ"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"የቅርብ ጊዜ መልዕክቶችን፣ ያመለጡ ጥሪዎች እና፣ የሁኔታ ዝመናዎችን ይመልከቱ"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"ውይይት"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"በአትረብሽ ባለበት ቆሟል"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> መልዕክት ልኳል"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ምስል ልኳል"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"የባትሪ መለኪያዎን የማንበብ ችግር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 999f4ab..fb6cba1 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1139,8 +1139,7 @@
     <string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"أدوات المحادثة"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"انقر على محادثة لإضافتها إلى \"الشاشة الرئيسية\"."</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"يمكنك الرجوع إلى هذه الأداة عندما تتلقّى بعض الرسائل."</string>
     <string name="priority_conversations" msgid="3967482288896653039">"المحادثات ذات الأولوية"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"المحادثات الحديثة"</string>
     <string name="okay" msgid="6490552955618608554">"حسنًا"</string>
@@ -1169,7 +1168,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"عرض أحدث الرسائل والمكالمات الفائتة والتغييرات في الحالة"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"محادثة"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"تم إيقاف الإشعار مؤقتًا من خلال ميزة \"عدم الإزعاج\""</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"تم إرسال رسالة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"تم إرسال صورة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"حدثت مشكلة أثناء قراءة مقياس مستوى شحن البطارية."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 110bf2e..4892730 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -32,14 +32,14 @@
     <string name="invalid_charger" msgid="4370074072117767416">"ইউএছবি জৰিয়তে চ্চাৰ্জ কৰিব নোৱাৰি। আপোনাৰ ডিভাইচৰ লগত পোৱা চ্চাৰ্জাৰটো ব্যৱহাৰ কৰক।"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"ইউএছবি জৰিয়তে চ্চাৰ্জ কৰিব নোৱাৰি"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"আপোনাৰ ডিভাইচৰ লগত পোৱা চ্চাৰ্জাৰটো ব্যৱহাৰ কৰক।"</string>
-    <string name="battery_low_why" msgid="2056750982959359863">"ছেটিং"</string>
+    <string name="battery_low_why" msgid="2056750982959359863">"ছেটিংসমূহ"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"বেটাৰি সঞ্চয়কাৰী অন কৰেনে?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"বেটাৰী সঞ্চয়কাৰীৰ বিষয়ে"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"অন কৰক"</string>
     <string name="battery_saver_start_action" msgid="4553256017945469937">"বেটাৰি সঞ্চয়কাৰী অন কৰক"</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"ছেটিংসমূহ"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"ৱাই-ফাই"</string>
-    <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীণ"</string>
     <string name="status_bar_settings_mute_label" msgid="914392730086057522">"মিউট"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="2151934479226017725">"স্বয়ং"</string>
     <string name="status_bar_settings_notifications" msgid="5285316949980621438">"জাননীসমূহ"</string>
@@ -343,7 +343,7 @@
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"অন কৰি থকা হৈছে…"</string>
     <string name="quick_settings_brightness_label" msgid="680259653088849563">"উজ্জ্বলতা"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
-    <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
+    <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীণ"</string>
     <string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"<xliff:g id="ID_1">%s</xliff:g> ম\'ড"</string>
     <string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"ঘূৰ্ণন লক কৰা হ’ল"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="1194988975270484482">"প\'ৰ্ট্ৰেইট"</string>
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"বাৰ্তালাপ খোলক"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"বাৰ্তালাপ ৱিজেট"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"আপোনাৰ গৃহ স্ক্ৰীনত কোনো বাৰ্তালাপ যোগ দিবলৈ সেইটোত টিপক"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"আপুনি কিবা বাৰ্তা পোৱাৰ পাছত ইয়াত পুনৰ চাওক"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"অগ্ৰাধিকাৰপ্ৰাপ্ত বাৰ্তালাপ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"শেহতীয়া বাৰ্তালাপ"</string>
     <string name="okay" msgid="6490552955618608554">"ঠিক আছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b47f251..a67a41a 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Söhbət vidcetləri"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Əsas ekranınıza əlavə etmək üçün söhbətə toxunun"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Mesaj gəldikdə yenidən buraya baxın"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Önəmli söhbətlər"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Son söhbətlər"</string>
     <string name="okay" msgid="6490552955618608554">"Oldu"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Son mesajlar, buraxılmış zənglər və status güncəlləmələrinə baxın"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Söhbət"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\"Narahat Etməyin\" rejimini tərəfindən durdurulub"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> mesaj göndərdi"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> şəkil göndərdi"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya ölçüsünü oxuyarkən problem yarandı"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 2bf6920..3cbe6ba 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1121,8 +1121,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Vidžeti za konverzaciju"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite konverzaciju da biste je dodali na početni ekran"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vratite se ovde kada dobijete neku poruku"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioritetne konverzacije"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nedavne konverzacije"</string>
     <string name="okay" msgid="6490552955618608554">"Važi"</string>
@@ -1151,7 +1150,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Pogledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Konverzacija"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pauzirano režimom Ne uznemiravaj"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> šalje poruku"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> šalje sliku"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 922ebb0..3e06a68 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Адкрытая размова"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Віджэты размовы"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Націсніце на размову, каб дадаць яе на галоўны экран"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Вярніцеся сюды, калі з\'явяцца паведамленні"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Прыярытэтныя размовы"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Нядаўнія размовы"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Глядзець нядаўнія паведамленні, прапушчаныя выклікі і абнаўленні стану"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Размова"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Прыпынена функцыяй \"Не турбаваць\""</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў паведамленне"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў відарыс"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Праблема з чытаннем індыкатара зараду акумулятара"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 21971d0..fafc9ee 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Приспособления за разговор"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Докоснете разговор, за да го добавите към началния си екран"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Проверете отново тук, когато получите съобщения"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Разговори с приоритет"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Скорошни разговори"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 8c02a0f..7c51625 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"খোলা কথোপকথন"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"কথোপকথন উইজেট"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"কোনও কথোপথন আপনার হোম স্ক্রিনে যোগ করার জন্য এতে ট্যাপ করুন"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"কোনও মেসেজ পেলে আবার এখানে দেখুন"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"গুরুত্বপূর্ণ কথোপকথন"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"সাম্প্রতিক কথোপকথন"</string>
     <string name="okay" msgid="6490552955618608554">"ঠিক আছে"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"সাম্প্রতিক মেসেজ, মিসড কল এবং স্ট্যাটাস সংক্রান্ত আপডেট দেখুন"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"কথোপকথন"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\'বিরক্ত করবে না\' মোডের মাধ্যমে পজ করা আছে"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> একটি মেসেজ পাঠিয়েছেন"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> একটি ছবি পাঠিয়েছেন"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 769da0a..02cdd7a 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1121,8 +1121,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Vidžeti za razgovor"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite razgovor da ga dodate na početni ekran"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vratite se ovdje kada dobijete neku poruku"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioritetni razgovori"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nedavni razgovori"</string>
     <string name="okay" msgid="6490552955618608554">"Uredu"</string>
@@ -1151,7 +1150,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Pregledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Razgovor"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pauzirala je funkcija Ne ometaj"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la sliku"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Došlo je do problema prilikom očitavanja mjerača stanja baterije"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 055e68a..a01d4fe 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toca una conversa per afegir-la a la teva pantalla d\'inici"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Torna a consultar aquesta pàgina quan rebis algun missatge"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Converses prioritàries"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Converses recents"</string>
     <string name="okay" msgid="6490552955618608554">"D\'acord"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Consulta els missatges recents, les trucades perdudes i les actualitzacions d\'estat"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Posat en pausa pel mode No molestis"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat un missatge"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat una imatge"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Hi ha hagut un problema en llegir el mesurador de la bateria"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6545eec..f3a5828 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgety konverzací"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Klepnutím na konverzaci ji přidáte na plochu"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vraťte se sem, až dostanete nějaké zprávy"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioritní konverzace"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Poslední konverzace"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Zobrazit poslední zprávy, zmeškané hovory a aktualizace stavu"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Konverzace"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pozastaveno funkcí Nerušit"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> posílá zprávu"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> posílá obrázek"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index caa47a9..53fb06c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Samtalewidgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tryk på en samtale for at føje den til din startskærm"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vend tilbage hertil, når du har fået beskeder"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioriterede samtaler"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Seneste samtaler"</string>
     <string name="okay" msgid="6490552955618608554">"Okay"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Se dine seneste beskeder, mistede opkald og statusopdateringer"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Samtale"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Sat på pause af Forstyr ikke"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en sms"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et billede"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at aflæse dit batteriniveau"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 7da6f88..82c8c58 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Unterhaltungs-Widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tippe auf eine Unterhaltung, um sie deinem Startbildschirm hinzuzufügen"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Wenn du Nachrichten empfängst, findest du sie hier"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Vorrangige Unterhaltungen"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Neueste Unterhaltungen"</string>
     <string name="okay" msgid="6490552955618608554">"Ok"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Letzte Nachrichten, verpasste Anrufe und Statusaktualisierungen ansehen"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Unterhaltung"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Durch „Bitte nicht stören“ pausiert"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> hat eine Nachricht gesendet"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> hat ein Bild gesendet"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem beim Lesen des Akkustands"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 11bc5ad..2ab27a7 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Γραφικά στοιχεία συνομιλίας"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Πατήστε μια συνομιλία για να την προσθέσετε στην αρχική οθόνη"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Ελέγξτε ξανά εδώ όταν λάβετε ορισμένα μηνύματα"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Συζητήσεις προτεραιότητας"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Πρόσφατες συζητήσεις"</string>
     <string name="okay" msgid="6490552955618608554">"Εντάξει"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Δείτε πρόσφατα μηνύματα, αναπάντητες κλήσεις και ενημερώσεις κατάστασης"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Συνομιλία"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Σε παύση από τη λειτουργία Μην ενοχλείτε"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε ένα μήνυμα"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε μια εικόνα"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Υπάρχει κάποιο πρόβλημα με την ανάγνωση του μετρητή μπαταρίας"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index f401fd4..7fec05a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Your recent conversations will show up here"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"Check back here once you get some messages"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index cef55f7..97624b6 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Your recent conversations will show up here"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"Check back here once you get some messages"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f401fd4..7fec05a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Your recent conversations will show up here"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"Check back here once you get some messages"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f401fd4..7fec05a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Conversation widgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tap a conversation to add it to your home screen"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Your recent conversations will show up here"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"Check back here once you get some messages"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 7fe3a63..cf89f22 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎Open conversation‎‏‎‎‏‎"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎Conversation widgets‎‏‎‎‏‎"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎Tap a conversation to add it to your Home screen‎‏‎‎‏‎"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎Your recent conversations will show up here‎‏‎‎‏‎"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‎‏‎Check back here once you get some messages‎‏‎‎‏‎"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎Priority conversations‎‏‎‎‏‎"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎Recent conversations‎‏‎‎‏‎"</string>
     <string name="okay" msgid="6490552955618608554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎Okay‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f41a02c..6de7754 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversación"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Presiona una conversación para agregarla a tu pantalla principal"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vuelve a consultar cuando recibas algunos mensajes"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversaciones prioritarias"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversaciones recientes"</string>
     <string name="okay" msgid="6490552955618608554">"Aceptar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b5d1b22..b58b0f6 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversación"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toca una conversación para añadirla a la pantalla de inicio"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vuelve cuando recibas algún mensaje"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversaciones prioritarias"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversaciones recientes"</string>
     <string name="okay" msgid="6490552955618608554">"Vale"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Consulta los mensajes recientes, las llamadas perdidas y los cambios de estado"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversación"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pausado por No molestar"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado un mensaje"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado una imagen"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"No se ha podido leer el indicador de batería"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 7d04f81..2afd6af 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Vestlusvidinad"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Puudutage vestlust, et lisada see oma avakuvale"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Tulge tagasi, kui olete mõne sõnumi saanud"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioriteetsed vestlused"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Hiljutised vestlused"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Vestlus"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Peatas režiim Mitte segada"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> saatis sõnumi"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> saatis pildi"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem akumõõdiku lugemisel"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 633c91f..64641d6 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Elkarrizketa-widgetak"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Sakatu elkarrizketa bat hasierako pantailan gehitzeko"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Itzuli geroago, zenbait mezu jasotakoan"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Lehentasunezko elkarrizketak"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Azken elkarrizketak"</string>
     <string name="okay" msgid="6490552955618608554">"Ados"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Ikusi azken mezuak, dei galduak eta egoerari buruzko informazio eguneratua"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Elkarrizketa"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Ez molestatzeko moduak pausatu du"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak irudi bat bidali du"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Arazo bat gertatu da bateria-neurgailua irakurtzean"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7420ad6..c71ee67 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ابزارک‌های مکالمه"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"روی مکالمه‌ای ضربه بزنید تا به «صفحه اصلی» اضافه شود"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"به‌محض اینکه چند پیام دریافت کردید، به اینجا سربزنید"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"مکالمه‌های اولویت‌دار"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"گفتگوهای اخیر"</string>
     <string name="okay" msgid="6490552955618608554">"تأیید"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"بیش‌از <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"دیدن به‌روزرسانی‌های وضعیت، تماس‌های بی‌پاسخ، و پیام‌های اخیر"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"مکالمه"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"با «مزاحم نشوید» موقتاً متوقف شده است"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> پیامی ارسال کرد"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> تصویری ارسال کرد"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"مشکلی در خواندن میزان باتری وجود دارد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 8c546f7..136ab7c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Keskusteluwidgetit"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Lisää keskustelu aloitusnäytölle napauttamalla sitä"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Palaa taas tänne, kun olet saanut viestejä"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Tärkeät keskustelut"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Uusimmat keskustelut"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Yli <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Katso viimeaikaiset viestit, vastaamattomat puhelut ja tilapäivitykset"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Keskustelu"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Älä häiritse ‑tilan keskeyttämä"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> lähetti viestin"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> lähetti kuvan"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ongelma akkumittarin lukemisessa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a6987f4..00457cd 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversation"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Touchez une conversation pour l\'ajouter à votre écran d\'accueil"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Revenez ici quand vous aurez reçu des messages"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversations prioritaires"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversations récentes"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Affichez les messages récents, les appels manqués et les mises à jour d\'état"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Interrompues par la fonctionnalité Ne pas déranger"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu lors de la lecture du niveau de charge de la pile"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d67cac4..3835cf7 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -733,8 +733,8 @@
     <string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string>
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, s\'affiche plus bas dans la section des conversations"</string>
-    <string name="notification_channel_summary_default" msgid="3282930979307248890">"Son ou vibreur, selon les paramètres du téléphone"</string>
-    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Son ou vibreur, selon les paramètres du téléphone. Les conversations provenant de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'affichent sous forme de bulles par défaut."</string>
+    <string name="notification_channel_summary_default" msgid="3282930979307248890">"Peut sonner ou vibrer en fonction des paramètres du téléphone"</string>
+    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Peut sonner ou vibrer en fonction des paramètres du téléphone. Les conversations provenant de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'affichent sous forme de bulles par défaut."</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Attire votre attention à l\'aide d\'un raccourci flottant vers ce contenu."</string>
     <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laisser le système déterminer si cette notification doit être accompagnée d\'un son ou d\'une vibration"</string>
     <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"&lt;b&gt;État :&lt;/b&gt; Élevée à la catégorie \"Par défaut\""</string>
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversation"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Appuyez sur une conversation pour l\'ajouter à votre écran d\'accueil"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Revenez quand vous aurez reçu des messages"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversations prioritaires"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversations récentes"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ de <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Voir les messages récents, les appels manqués et les notifications d\'état"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Mise en pause par Ne pas déranger"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 5f47203..ffe51cc 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toca unha conversa para engadila á pantalla de inicio"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Volve aquí despois de recibir mensaxes"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversas prioritarias"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
     <string name="okay" msgid="6490552955618608554">"De acordo"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ de <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Consulta as mensaxes recentes, as chamadas perdidas e as actualizacións dos estados"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Púxose en pausa debido ao modo Non molestar"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha mensaxe"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha imaxe"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 3f4d524..96bfdd7 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"વાતચીત ખોલો"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"વાતચીતના વિજેટ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"તમારી હોમ સ્ક્રીનમાં વાતચીત ઉમેરવા માટે તેના પર ટૅપ કરો"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"તમારી તાજેતરની વાતચીતો અહીં બતાવવામાં આવશે"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"એકવાર તમને અમુક સંદેશા મળે પછી ફરીથી અહીં ચેક કરો"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"પ્રાધાન્યતા ધરાવતી વાતચીતો"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"તાજેતરની વાતચીતો"</string>
     <string name="okay" msgid="6490552955618608554">"ઓકે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 47a9820..bf32e20 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"बातचीत विजेट"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"किसी बातचीत को होम स्क्रीन पर जोड़ने के लिए, उस बातचीत पर टैप करें"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"हाल ही में हुई बातचीत यहां दिखेंगी"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"नए मैसेज आने पर यहां देखें"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"प्राथमिकता वाली बातचीत"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"हाल ही में की गई बातचीत"</string>
     <string name="okay" msgid="6490552955618608554">"ठीक है"</string>
@@ -1144,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"हाल के मैसेज, मिस्ड कॉल, और स्टेटस अपडेट देखें"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"बातचीत"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\'परेशान न करें\' की वजह से सूचनाएं नहीं दिख रहीं"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ने एक मैसेज भेजा है"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ने एक इमेज भेजी है"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"आपके डिवाइस के बैटरी मीटर की रीडिंग लेने में समस्या आ रही है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index ee13344f..0c039c1 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1121,8 +1121,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgeti razgovora"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Dodirnite razgovor da biste ga dodali na početni zaslon"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Ponovno provjerite ovdje kad dobijete poruke"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioritetni razgovori"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nedavni razgovori"</string>
     <string name="okay" msgid="6490552955618608554">"U redu"</string>
@@ -1151,7 +1150,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Pogledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Razgovor"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pauzirala značajka Ne uznemiravaj"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> šalje poruku"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> poslao je sliku"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem s očitavanjem mjerača baterije"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index fae365d..8908b2a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Beszélgetési modulok"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Koppintson a kívánt beszélgetésre a kezdőképernyőre való felvételhez"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Térjen vissza ide, miután kapott néhány üzenetet"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Fontos beszélgetések"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Legutóbbi beszélgetések"</string>
     <string name="okay" msgid="6490552955618608554">"Rendben"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Megtekintheti a legutóbbi üzeneteket, a nem fogadott hívásokat és az állapotfrissítéseket."</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Beszélgetés"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"A Ne zavarjanak mód által szüneteltetve"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> üzenetet küldött"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> képet küldött"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probléma merült fel az akkumulátor-töltésmérő olvasásakor"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 2063d43..5818223 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Զրույցի վիջեթներ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Հպեք զրույցին՝ այն հիմնական էկրանին ավելացնելու համար"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Ձեր վերջին զրույցները կցուցադրվեն այստեղ"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"Վերադարձեք այստեղ, երբ հաղորդագրություններ ստանաք"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Կարևոր զրույցներ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Վերջին հաղորդագրությունները"</string>
     <string name="okay" msgid="6490552955618608554">"Եղավ"</string>
@@ -1144,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Տեսեք վերջին հաղորդագրությունները, բաց թողնված զանգերը և կարգավիճակի մասին թարմացումները"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Զրույց"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Դադարեցվել է «Չանհանգստացնել» գործառույթի կողմից"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հաղորդագրություն է ուղարկել"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը պատկեր է ուղարկել"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 7da7482..072b691 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widget Percakapan"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Ketuk percakapan untuk menambahkannya ke Layar utama"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Periksa kembali setelah Anda mendapatkan pesan"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Percakapan prioritas"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Percakapan terbaru"</string>
     <string name="okay" msgid="6490552955618608554">"Oke"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Lihat pesan terbaru, panggilan tak terjawab, dan pembaruan status"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Percakapan"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Dijeda oleh fitur Jangan Ganggu"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> mengirim pesan"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> mengirim gambar"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi masalah saat membaca indikator baterai"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index a996cb1..9d54e6f 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Samtalsgræjur"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Ýttu á samtal til að bæta því á heimaskjáinn"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Komdu aftur hingað þegar þú hefur fengið skilaboð"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Forgangssamtöl"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nýleg samtöl"</string>
     <string name="okay" msgid="6490552955618608554">"Í lagi"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Sjá nýleg skilboð, ósvöruð símtöl og stöðuuppfærslur"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Samtal"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Sett í bið af „Ónáðið ekki“"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> sendi skilaboð"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sendi mynd"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Vandamál við að lesa stöðu rafhlöðu"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8cdc484..3063e84 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -734,7 +734,7 @@
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"Nessun suono o vibrazione"</string>
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nessun suono o vibrazione e appare più in basso nella sezione delle conversazioni"</string>
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"Può suonare o vibrare in base alle impostazioni del telefono"</string>
-    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Può suonare o vibrare in base alle impostazioni del telefono. Le conversazioni di <xliff:g id="APP_NAME">%1$s</xliff:g> appaiono come bolla per impostazione predefinita."</string>
+    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Può suonare o vibrare in base alle impostazioni del telefono. Conversazioni dalla bolla <xliff:g id="APP_NAME">%1$s</xliff:g> per impostazione predefinita."</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantiene la tua attenzione con una scorciatoia mobile a questi contenuti."</string>
     <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Fai stabilire al sistema se questa notifica deve emettere suoni o vibrazioni"</string>
     <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"&lt;b&gt;Stato:&lt;/b&gt; promossa a Predefinita"</string>
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widget di conversazione"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tocca una conversazione per aggiungerla alla schermata Home"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Torna qui quando avrai ricevuto qualche messaggio"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversazioni prioritarie"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversazioni recenti"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Visualizza messaggi recenti, chiamate senza risposta e aggiornamenti dello stato"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversazione"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"In pausa in base alla modalità Non disturbare"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un messaggio"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un\'immagine"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 75a9d75..14b7c64 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -750,7 +750,7 @@
     <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"מוצגת בחלק העליון של קטע ההתראות וכתמונת פרופיל במסך הנעילה"</string>
     <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה"</string>
     <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מפריעה במצב \'נא לא להפריע\'"</string>
-    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה צפה ומפריעה במצב \'נא לא להפריע\'"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה הצפה ומפריעה במצב \'נא לא להפריע\'"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"בעדיפות גבוהה"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string>
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ווידג\'טים של שיחות"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"יש להקיש על שיחה כדי להוסיף אותה למסך הבית"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"אפשר לחזור לכאן ולהתעדכן לאחר קבלת מספר הודעות"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"שיחות בעדיפות גבוהה"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"שיחות אחרונות"</string>
     <string name="okay" msgid="6490552955618608554">"בסדר"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"ההודעות האחרונות, שיחות שלא נענו ועדכוני סטטוס"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"שיחה"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"ההתראה הושהתה על ידי \'נא לא להפריע\'"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה הודעה"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה תמונה"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 065167a..d320625 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -190,12 +190,12 @@
     <string name="accessibility_compatibility_zoom_example" msgid="2617218726091234073">"小さい画面から大きい画面に拡大。"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetoothに接続済み。"</string>
     <string name="accessibility_bluetooth_disconnected" msgid="7195823280221275929">"Bluetoothが切断されました。"</string>
-    <string name="accessibility_no_battery" msgid="3789287732041910804">"バッテリー残量: なし"</string>
-    <string name="accessibility_battery_one_bar" msgid="8868347318237585329">"バッテリー残量: レベル1"</string>
-    <string name="accessibility_battery_two_bars" msgid="7895789999668425551">"バッテリー残量: レベル2"</string>
-    <string name="accessibility_battery_three_bars" msgid="118341923832368291">"バッテリー残量: レベル3"</string>
-    <string name="accessibility_battery_full" msgid="1480463938961288494">"バッテリー残量: フル"</string>
-    <string name="accessibility_battery_unknown" msgid="1807789554617976440">"バッテリー残量は不明です。"</string>
+    <string name="accessibility_no_battery" msgid="3789287732041910804">"電池残量:なし"</string>
+    <string name="accessibility_battery_one_bar" msgid="8868347318237585329">"電池残量:レベル1"</string>
+    <string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池残量:レベル2"</string>
+    <string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池残量:レベル3"</string>
+    <string name="accessibility_battery_full" msgid="1480463938961288494">"電池残量:満"</string>
+    <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池残量は不明です。"</string>
     <string name="accessibility_wifi_name" msgid="4863440268606851734">"<xliff:g id="WIFI">%s</xliff:g>に接続しました。"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>に接続しました。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>に接続されています。"</string>
@@ -227,8 +227,8 @@
     <string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN は ON です。"</string>
     <string name="accessibility_no_sims" msgid="5711270400476534667">"SIMカードが挿入されていません。"</string>
     <string name="accessibility_battery_details" msgid="6184390274150865789">"電池の詳細情報を開きます"</string>
-    <string name="accessibility_battery_level" msgid="5143715405241138822">"バッテリー残量: <xliff:g id="NUMBER">%d</xliff:g>パーセント"</string>
-    <string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"バッテリー残量: <xliff:g id="PERCENTAGE">%1$s</xliff:g>、およそ <xliff:g id="TIME">%2$s</xliff:g> にバッテリー切れ(使用状況に基づく)"</string>
+    <string name="accessibility_battery_level" msgid="5143715405241138822">"電池残量: <xliff:g id="NUMBER">%d</xliff:g>パーセント"</string>
+    <string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"電池残量: <xliff:g id="PERCENTAGE">%1$s</xliff:g>、およそ <xliff:g id="TIME">%2$s</xliff:g> に電池切れ(使用状況に基づく)"</string>
     <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"電池充電中: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>パーセント"</string>
     <string name="accessibility_settings_button" msgid="2197034218538913880">"システム設定。"</string>
     <string name="accessibility_notifications_button" msgid="3960913924189228831">"通知。"</string>
@@ -255,7 +255,7 @@
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="2230487165558877262">"Wi-FiをOFFにしました。"</string>
     <string name="accessibility_quick_settings_wifi_changed_on" msgid="1490362586009027611">"Wi-FiをONにしました。"</string>
     <string name="accessibility_quick_settings_mobile" msgid="1817825313718492906">"モバイル: <xliff:g id="SIGNAL">%1$s</xliff:g>、<xliff:g id="TYPE">%2$s</xliff:g>、<xliff:g id="NETWORK">%3$s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_battery" msgid="533594896310663853">"バッテリー<xliff:g id="STATE">%s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_battery" msgid="533594896310663853">"電池<xliff:g id="STATE">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_airplane_off" msgid="1275658769368793228">"機内モードがOFFです。"</string>
     <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"機内モードがONです。"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"機内モードをOFFにしました。"</string>
@@ -335,7 +335,7 @@
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth(デバイス数<xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="6375098046500790870">"Bluetooth OFF"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ペア設定されたデバイスがありません"</string>
-    <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
+    <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電池 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
     <string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"オーディオ"</string>
     <string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ヘッドセット"</string>
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"入力"</string>
@@ -414,7 +414,7 @@
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"日の出まで"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> に ON"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> まで"</string>
-    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ダークモード"</string>
+    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ダークテーマ"</string>
     <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"バッテリー セーバー"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"日の入りに ON"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"日の出まで"</string>
@@ -655,8 +655,8 @@
     <string name="output_service_wifi" msgid="9003667810868222134">"Wi-Fi"</string>
     <string name="output_service_bt_wifi" msgid="7186882540475524124">"Bluetooth と Wi-Fi"</string>
     <string name="system_ui_tuner" msgid="1471348823289954729">"システムUI調整ツール"</string>
-    <string name="show_battery_percentage" msgid="6235377891802910455">"内蔵バッテリーの残量の割合を表示する"</string>
-    <string name="show_battery_percentage_summary" msgid="9053024758304102915">"充電していないときにはバッテリー残量の割合をステータスバーアイコンに表示する"</string>
+    <string name="show_battery_percentage" msgid="6235377891802910455">"内蔵電池の残量の割合を表示する"</string>
+    <string name="show_battery_percentage_summary" msgid="9053024758304102915">"充電していないときには電池残量の割合をステータスバーアイコンに表示する"</string>
     <string name="quick_settings" msgid="6211774484997470203">"クイック設定"</string>
     <string name="status_bar" msgid="4357390266055077437">"ステータスバー"</string>
     <string name="overview" msgid="3522318590458536816">"最近"</string>
@@ -693,7 +693,7 @@
     <string name="remove_from_settings_prompt" msgid="551565437265615426">"設定からシステムUI調整ツールを削除して、全機能の使用を停止しますか?"</string>
     <string name="activity_not_found" msgid="8711661533828200293">"アプリがデバイスにインストールされていません"</string>
     <string name="clock_seconds" msgid="8709189470828542071">"時計の秒を表示"</string>
-    <string name="clock_seconds_desc" msgid="2415312788902144817">"ステータスバーに時計の秒を表示します。バッテリー使用量に影響する可能性があります。"</string>
+    <string name="clock_seconds_desc" msgid="2415312788902144817">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
     <string name="qs_rearrange" msgid="484816665478662911">"クイック設定を並べ替え"</string>
     <string name="show_brightness" msgid="6700267491672470007">"クイック設定に明るさ調整バーを表示する"</string>
     <string name="experimental" msgid="3549865454812314826">"試験運用版"</string>
@@ -850,7 +850,7 @@
     <string name="volume_and_do_not_disturb" msgid="502044092739382832">"サイレント モード"</string>
     <string name="volume_dnd_silent" msgid="4154597281458298093">"音量ボタンのショートカット"</string>
     <string name="volume_up_silent" msgid="1035180298885717790">"音量大ボタンでサイレント モードを OFF にします"</string>
-    <string name="battery" msgid="769686279459897127">"バッテリー"</string>
+    <string name="battery" msgid="769686279459897127">"電池"</string>
     <string name="clock" msgid="8978017607326790204">"時計"</string>
     <string name="headset" msgid="4485892374984466437">"ヘッドセット"</string>
     <string name="accessibility_long_click_tile" msgid="210472753156768705">"設定を開く"</string>
@@ -959,7 +959,7 @@
     <string name="tuner_menu" msgid="363690665924769420">"メニュー"</string>
     <string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> アプリ"</string>
     <string name="notification_channel_alerts" msgid="3385787053375150046">"アラート"</string>
-    <string name="notification_channel_battery" msgid="9219995638046695106">"バッテリー"</string>
+    <string name="notification_channel_battery" msgid="9219995638046695106">"電池"</string>
     <string name="notification_channel_screenshot" msgid="7665814998932211997">"スクリーンショット"</string>
     <string name="notification_channel_general" msgid="4384774889645929705">"一般メッセージ"</string>
     <string name="notification_channel_storage" msgid="2720725707628094977">"ストレージ"</string>
@@ -983,7 +983,7 @@
     <string name="qs_dnd_keep" msgid="3829697305432866434">"設定を維持"</string>
     <string name="qs_dnd_replace" msgid="7712119051407052689">"設定を変更"</string>
     <string name="running_foreground_services_title" msgid="5137313173431186685">"バックグラウンドで実行中のアプリ"</string>
-    <string name="running_foreground_services_msg" msgid="3009459259222695385">"タップしてバッテリーやデータの使用量を確認"</string>
+    <string name="running_foreground_services_msg" msgid="3009459259222695385">"タップして電池やデータの使用量を確認"</string>
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"モバイルデータを OFF にしますか?"</string>
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g>でデータやインターネットにアクセスできなくなります。インターネットには Wi-Fi からのみ接続できます。"</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"携帯通信会社"</string>
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"会話ウィジェット"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"会話をタップするとホーム画面に追加されます"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"最近の会話がここに表示されます"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"メッセージを受信すると、ここに表示されます"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"優先度の高い会話"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"最近の会話"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1144,10 +1144,11 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> 件以上"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"最近のメッセージ、不在着信、最新のステータスが表示されます"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"会話"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"サイレント モードにより一時停止"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> さんからメッセージが届きました"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> さんが画像を送信しました"</string>
-    <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"バッテリー残量の読み込み中に問題が発生しました"</string>
+    <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"電池残量の読み込み中に問題が発生しました"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"アラーム未設定"</string>
     <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"指紋認証センサー"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index dd66db39..c7a52e99 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"მიმოწერის გახსნა"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"საუბრის ვიჯეტები"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"შეეხეთ საუბარს მის თქვენს მთავარ ეკრანზე დასამატებლად"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"შეამოწმეთ ეს სივრცე, როცა რაღაც რაოდენობის შეტყობინებებს მიიღებთ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"პრიორიტეტული საუბრები"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ბოლო მიმოწერები"</string>
     <string name="okay" msgid="6490552955618608554">"კარგი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c6a9e9a..5abd6c7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Ашық әңгіме"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Әңгіме виджеттері"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Негізгі экранға қосқыңыз келетін әңгімені түртіңіз."</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Хабарлар алғаннан кейін осында оралыңыз."</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Маңызды әңгімелер"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Соңғы әңгімелер"</string>
     <string name="okay" msgid="6490552955618608554">"Жарайды"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Соңғы хабарларды, өткізіп алған қоңыраулар мен жаңартылған күйлерді көруге болады."</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Әңгіме"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\"Мазаламау\" режимі арқылы кідіртілді."</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> хабар жіберді."</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сурет жіберді."</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батарея зарядының дерегі алынбай жатыр"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 7a586cd..3291ada 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"បើកការសន្ទនា"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ធាតុ​ក្រាហ្វិកនៃការសន្ទនា"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ចុចការសន្ទនា ដើម្បីបញ្ចូលវាទៅក្នុងអេក្រង់ដើមរបស់អ្នក"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"ត្រឡប់មក​មើលនៅទីនេះវិញ នៅពេលអ្នក​ទទួលបានសារ​មួយចំនួន"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ការសន្ទនា​អាទិភាព"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ការសន្ទនាថ្មីៗ"</string>
     <string name="okay" msgid="6490552955618608554">"យល់ព្រម"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"មើលព័ត៌មាន​ថ្មីៗ​អំពីស្ថានភាព ការខកខាន​ទទួល និងសារថ្មីៗ"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"ការ​សន្ទនា"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"បានផ្អាក​ដោយមុខងារ​កុំរំខាន"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើសារ"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> បាន​ផ្ញើ​រូបភាព"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"មានបញ្ហាក្នុង​ការអាន​ឧបករណ៍រង្វាស់កម្រិតថ្មរបស់អ្នក"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 41b6c44..c923550 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"ಸಂಭಾಷಣೆಯನ್ನು ತೆರೆಯಿರಿ"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ಸಂಭಾಷಣೆ ವಿಜೆಟ್‌ಗಳು"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ಸಂಭಾಷಣೆಯನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಸೇರಿಸಲು ಅದನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"ನೀವು ಕೆಲವು ಸಂದೇಶಗಳನ್ನು ಪಡೆದ ನಂತರ ಇಲ್ಲಿ ಮತ್ತೆ ಪರಿಶೀಲಿಸಿ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ಆದ್ಯತೆಯ ಸಂಭಾಷಣೆಗಳು"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ಇತ್ತೀಚಿನ ಸಂಭಾಷಣೆಗಳು"</string>
     <string name="okay" msgid="6490552955618608554">"ಸರಿ"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"ಇತ್ತೀಚಿನ ಸಂದೇಶಗಳು, ಮಿಸ್ಡ್ ಕಾಲ್‌ಗಳು ಮತ್ತು ಸ್ಥಿತಿ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"ಸಂಭಾಷಣೆ"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\'ಅಡಚಣೆ ಮಾಡಬೇಡಿ\' ನಿಂದ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1e48ebd..5a1e57a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"대화 열기"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"대화 위젯"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"대화를 탭하여 홈 화면에 추가하세요."</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"메시지를 받으면 여기서 다시 확인해 주세요."</string>
     <string name="priority_conversations" msgid="3967482288896653039">"우선순위 대화"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"최근 대화"</string>
     <string name="okay" msgid="6490552955618608554">"확인"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"최근 메시지, 부재중 전화, 상태 업데이트 보기"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"대화"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"방해 금지 모드로 인해 일시중지됨"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>님이 메시지를 보냈습니다."</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>님이 이미지를 보냈습니다."</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index bfc899c..13609cf 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Ачык сүйлөшүү"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Сүйлөшүүлөр виджеттери"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Сүйлөшүүнү башкы экранга кошуу үчүн таптап коюңуз"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Билдирүүлөрдү алгандан кийин бул жерди кайрадан текшериңиз"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Маанилүү сүйлөшүүлөр"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Акыркы сүйлөшүүлөр"</string>
     <string name="okay" msgid="6490552955618608554">"Макул"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Акыркы билдирүүлөрдү, жооп берилбеген чалууларды жана статустардын жаңырганын көрөсүз"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Сүйлөшүү"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\"Тынчымды алба\" режими тындырды"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> билдирүү жөнөттү"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сүрөт жөнөттү"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батареяңыздын кубаты аныкталбай жатат"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 27d6848..f708b98 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ວິດເຈັດການສົນທະນາ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ແຕະໃສ່ການສົນທະນາໃດໜຶ່ງເພື່ອເພີ່ມມັນໃສ່ໂຮມສະກຣີນຂອງທ່ານ"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"ການສົນທະນາຫຼ້າສຸດຂອງທ່ານຈະສະແດງຢູ່ບ່ອນນີ້"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"ກັບມາກວດເບິ່ງຢູ່ບ່ອນນີ້ຄືນໃໝ່ຫຼັງຈາກທີ່ທ່ານໄດ້ຮັບຂໍ້ຄວາມ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ການສົນທະນາສຳຄັນ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ການສົນທະນາຫຼ້າສຸດ"</string>
     <string name="okay" msgid="6490552955618608554">"ຕົກລົງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 04dc3fc..0da285da 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Pokalbio valdikliai"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Palieskite pokalbį, kad pridėtumėte jį prie pagrindinio ekrano"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Sugrįžkite, kai gausite pranešimų"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Svarbiausi pokalbiai"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Paskutiniai pokalbiai"</string>
     <string name="okay" msgid="6490552955618608554">"Gerai"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> +"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Peržiūrėkite naujausius pranešimus, praleistus skambučius ir būsenos atnaujinimus"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Pokalbis"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pristabdyta dėl netrukdymo režimo"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė pranešimą"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė vaizdą"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nuskaitant akumuliatoriaus skaitiklį iškilo problema"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ade61cd..abd59e8 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1121,8 +1121,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Sarunu logrīki"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Pieskarieties kādai sarunai, lai pievienotu to savam sākuma ekrānam."</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Atgriezieties šeit, kad būsiet saņēmis ziņojumus."</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioritārās sarunas"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Jaunākās sarunas"</string>
     <string name="okay" msgid="6490552955618608554">"Labi"</string>
@@ -1151,7 +1150,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Skatiet jaunākos ziņojumus, neatbildētos zvanus un statusa atjauninājumus."</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Saruna"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Rādīšana pārtraukta režīma Netraucēt dēļ"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja ziņojumu"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja attēlu"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nevar iegūt informāciju par akumulatora uzlādes līmeni."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 4e4793a..545c42c 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Започни разговор"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Виџети за разговор"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Допрете на разговор за да го додадете на вашиот почетен екран"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Вратете се тука кога ќе добиете пораки"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Приоритетни разговори"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Неодамнешни разговори"</string>
     <string name="okay" msgid="6490552955618608554">"Во ред"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Видете ги неодамнешните пораки, пропуштени повици и промени на статусот"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Паузирано од „Не вознемирувај“"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> испрати порака"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> испрати слика"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем при читањето на мерачот на батеријата"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index d96aa06..d7dc7d8 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -734,7 +734,7 @@
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല"</string>
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ശബ്‌ദമോ വൈബ്രേഷനോ ഇല്ല, സംഭാഷണ വിഭാഗത്തിന് താഴെയായി ദൃശ്യമാകും"</string>
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ്/വൈബ്രേറ്റ് ചെയ്യും"</string>
-    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ്/വൈബ്രേറ്റ് ചെയ്‌തേക്കാം. <xliff:g id="APP_NAME">%1$s</xliff:g>-ൽ നിന്നുള്ള സംഭാഷണങ്ങൾ ഡിഫോൾട്ടായി ബബിൾ ചെയ്യുന്നു."</string>
+    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ് ചെയ്‌തേക്കാം അല്ലെങ്കിൽ വൈബ്രേറ്റ് ചെയ്‌തേക്കാം. <xliff:g id="APP_NAME">%1$s</xliff:g>-ൽ നിന്നുള്ള സംഭാഷണങ്ങൾ ഡിഫോൾട്ടായി ബബിൾ ആവുന്നു."</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ഈ ഉള്ളടക്കത്തിലേക്ക് ഒരു ഫ്ലോട്ടിംഗ് കുറുക്കുവഴി ഉപയോഗിച്ച് നിങ്ങളുടെ ശ്രദ്ധ നിലനിർത്തുന്നു."</string>
     <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ഈ അറിയിപ്പ് വരുമ്പോൾ ശബ്‌ദിക്കുകയാണോ വൈബ്രേറ്റ് ചെയ്യുകയാണോ വേണ്ടതെന്ന് നിർണ്ണയിക്കാൻ സിസ്‌റ്റത്തെ അനുവദിക്കുക"</string>
     <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"&lt;b&gt;നില:&lt;/b&gt; ഡിഫോൾട്ടാക്കി പ്രമോട്ട് ചെയ്‌തു"</string>
@@ -744,7 +744,7 @@
     <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു"</string>
     <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു, ഒരു ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു"</string>
     <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
-    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു, ഒരു ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്‌ക്കുന്നില്ല"</string>
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"സംഭാഷണ വിജറ്റുകൾ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"നിങ്ങളുടെ ഹോം സ്‌ക്രീനിൽ ചേർക്കാൻ സംഭാഷണത്തിൽ ടാപ്പ് ചെയ്യുക"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"കുറച്ച് സന്ദേശങ്ങൾ ലഭിച്ച ശേഷം ഇവിടെ വീണ്ടും പരിശോധിക്കൂ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"മുൻഗണനാ സംഭാഷണങ്ങൾ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"അടുത്തിടെയുള്ള സംഭാഷണങ്ങൾ"</string>
     <string name="okay" msgid="6490552955618608554">"ശരി"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"അടുത്തിടെയുള്ള സന്ദേശങ്ങൾ, മിസ്‌ഡ് കോൾ, സ്റ്റാറ്റസ് അപ്‌ഡേറ്റുകൾ എന്നിവ കാണൂ"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"സംഭാഷണം"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\'ശല്യപ്പെടുത്തരുത്\' ഓണായതിനാൽ തൽക്കാലം നിർത്തി"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു സന്ദേശം അയച്ചു"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു ചിത്രം അയച്ചു"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"നിങ്ങളുടെ ബാറ്ററി മീറ്റർ വായിക്കുന്നതിൽ പ്രശ്‌നമുണ്ട്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 900fbd8..897e074 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Харилцан яриаг нээх"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Харилцан ярианы жижиг хэрэгслүүд"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Үндсэн нүүрэндээ нэмэх харилцан яриаг товшино уу"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Та зарим мессеж авсныхаа дараа эндээс буцаж шалгана уу"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Чухал харилцан яриа"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Саяхны харилцан яриа"</string>
     <string name="okay" msgid="6490552955618608554">"За"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Саяхны мессеж, аваагүй дуудлага болон төлөвийн шинэчлэлтийг харах"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Харилцан яриа"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Бүү саад бол горимоор түр зогсоосон"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> мессеж илгээсэн"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> зураг илгээсэн"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Таны батарей хэмжигчийг уншихад асуудал гарлаа"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5dd7abd..8737b94 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"संभाषण उघडा"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"संभाषण विजेट"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"तुमच्या होम स्क्रीन वर संभाषण जोडण्यासाठी त्यावर टॅप करा"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"तुम्हाला काही मेसेज मिळाल्यावर येथे पुन्हा पाहा"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"प्राधान्य दिलेली संभाषणे"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"अलीकडील संभाषणे"</string>
     <string name="okay" msgid="6490552955618608554">"ओके"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"अलीकडील मेसेज, मिस्ड कॉल आणि स्टेटस अपडेट पाहा"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"संभाषण"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"व्यत्यय आणू नका द्वारे थांबवले गेले"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> यांनी मेसेज पाठवला"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> यांनी इमेज पाठवली"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"तुमचे बॅटरी मीटर वाचताना समस्या आली"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 28ad7a7..8a3b4ce 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widget perbualan"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Ketik perbualan untuk menambahkan perbualan itu pada skrin Utama anda"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Semak di sini semula selepas anda mendapat beberapa mesej"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Perbualan keutamaan"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Perbualan terbaharu"</string>
     <string name="okay" msgid="6490552955618608554">"Okey"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Lihat mesej terbaharu, panggilan terlepas dan kemaskinian status"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Perbualan"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Dijeda oleh Jangan Ganggu"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> menghantar mesej"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> menghantar imej"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Masalah membaca meter bateri anda"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 54d1a5f..af80198 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -734,7 +734,7 @@
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ"</string>
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ၊ စကားဝိုင်းကဏ္ဍ၏ အောက်ပိုင်းတွင် မြင်ရသည်"</string>
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"ဖုန်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် သို့မဟုတ် တုန်ခါနိုင်သည်"</string>
-    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ဖုန်းဆက်တင်ပေါ် အခြေခံပြီး အသံမြည် (သို့) တုန်ခါနိုင်သည်။ <xliff:g id="APP_NAME">%1$s</xliff:g> မှ စကားဝိုင်းများကို ပူဖောင်းကွက်ဖြင့် အလိုအလျောက်ပြသည်။"</string>
+    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ဖုန်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် သို့မဟုတ် တုန်ခါနိုင်သည်။ မူရင်းသတ်မှတ်ချက်အဖြစ် <xliff:g id="APP_NAME">%1$s</xliff:g> မှ စကားဝိုင်းများကို ပူဖောင်းကွက်ဖြင့် ပြသည်။"</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"အကြောင်းအရာကို floating shortcut ကိုသုံး၍ အာရုံစိုက်လာအောင်လုပ်ပါ။"</string>
     <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ဤအကြောင်းကြားချက်က အသံ သို့မဟုတ် တုန်ခါမှု ပေးရန် သင့်/မသင့်ကို စနစ်က ဆုံးဖြတ်ပါစေ"</string>
     <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"&lt;b&gt;အခြေအနေ-&lt;/b&gt; မူရင်းသို့ ချိန်ညှိထားသည်"</string>
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"စကားဝိုင်းကို ဖွင့်ရန်"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"စကားဝိုင်း ဝိဂျက်များ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"စကားဝိုင်းကို သင်၏ ‘ပင်မစာမျက်နှာ’ သို့ထည့်ရန် တို့ပါ"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"သင်၏မကြာသေးမီက စကားဝိုင်းများကို ဤနေရာတွင် ပြပါမည်"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"မက်ဆေ့ဂျ်အချို့ရလျှင် ဤနေရာသို့ ပြန်လာကြည့်ပါ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ဦးစားပေး စကားဝိုင်းများ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"မကြာသေးမီက စကားဝိုင်းများ"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1144,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"မကြာသေးမီက မက်ဆေ့ဂျ်၊ လွတ်သွားသောခေါ်ဆိုမှုနှင့် အခြေအနေအပ်ဒိတ်များကို ကြည့်နိုင်သည်"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"စကားဝိုင်း"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"‘မနှောင့်ယှက်ရ’ ဖြင့် ခဏရပ်ထားသည်"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> က မက်ဆေ့ဂျ်ပို့လိုက်သည်"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> က ပုံပို့လိုက်သည်"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"သင်၏ ဘက်ထရီမီတာကို ဖတ်ရာတွင် ပြဿနာရှိနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c549deb..d6271c0 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Samtalemoduler"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Trykk på en samtale for å legge den til på startskjermen"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Sjekk her igjen når du mottar noen meldinger"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioriterte samtaler"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nylige samtaler"</string>
     <string name="okay" msgid="6490552955618608554">"Ok"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Se nylige meldinger, tapte anrop og statusoppdateringer"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Samtale"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Satt på pause av «Ikke forstyrr»"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en melding"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et bilde"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kunne ikke lese batterimåleren"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index b9ef04f..2159bf9 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"वार्तालाप खोल्नुहोस्"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"वार्तालापसम्बन्धी विजेटहरू"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"कुनै वार्तालाप होम स्क्रिनमा हाल्न उक्त वार्तालापमा ट्याप गर्नुहोस्"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"तपाईंले कुनै म्यासेज प्राप्त गरेपछि यहाँ आएर सो म्यासेज हेर्नुहोस्"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"महत्त्वपूर्ण वार्तालापहरू"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"हालसालैका वार्तालापहरू"</string>
     <string name="okay" msgid="6490552955618608554">"ठिक छ"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 07decdf..56a95f5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Gesprekswidgets"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tik op een gesprek om het toe te voegen aan je startscherm"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Kom hier terug zodra je wat berichten hebt"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioriteitsgesprekken"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Recente gesprekken"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Bekijk recente berichten, gemiste gesprekken en statusupdates"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Gesprek"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Onderbroken door Niet storen"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> heeft een bericht gestuurd"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> heeft een afbeelding gestuurd"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem bij het lezen van je batterijmeter"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index f4b3b3e..22fe336 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"ବାର୍ତ୍ତାଳାପ ଖୋଲନ୍ତୁ"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ବାର୍ତ୍ତାଳାପ ୱିଜେଟଗୁଡ଼ିକ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ଏକ ବାର୍ତ୍ତାଳାପକୁ ଆପଣଙ୍କ ମୂଳସ୍କ୍ରିନରେ ଯୋଗ କରିବା ପାଇଁ ସେଥିରେ ଟାପ୍ କରନ୍ତୁ"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"ଆପଣ କିଛି ମେସେଜ୍ ପାଇଲେ ଏଠାରେ ପୁଣି ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ପ୍ରାଥମିକତା ଦିଆଯାଇଥିବା ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ବର୍ତ୍ତମାନର ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
     <string name="okay" msgid="6490552955618608554">"ଠିକ୍ ଅଛି"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"ବର୍ତ୍ତମାନର ମେସେଜ୍, ମିସ୍ଡ କଲ୍ ଏବଂ ସ୍ଥିତି ଅପଡେଟଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"ବାର୍ତ୍ତାଳାପ"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଦ୍ୱାରା ବିରତ କରାଯାଇଛି"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ମେସେଜ୍ ପଠାଇଛନ୍ତି"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ଛବି ପଠାଇଛନ୍ତି"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ମିଟର୍ ପଢ଼ିବାରେ ସମସ୍ୟା ହେଉଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 7f96ea8..08789cd 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"ਗੱਲਬਾਤ ਵਿਜੇਟ"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਕੋਈ ਗੱਲਬਾਤ ਚੁਣੋ"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"ਤੁਹਾਨੂੰ ਕੁਝ ਸੁਨੇਹੇ ਮਿਲਣ \'ਤੇ, ਉਹਨਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਵਾਪਸ ਇੱਥੇ ਆਓ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ਤਰਜੀਹੀ ਗੱਲਾਂਬਾਤਾਂ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ਹਾਲੀਆ ਗੱਲਾਂਬਾਤਾਂ"</string>
     <string name="okay" msgid="6490552955618608554">"ਠੀਕ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 51a9f37..f1a8a84 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widżety Rozmowa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Kliknij rozmowę, aby dodać ją do ekranu głównego"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Tu pojawią się otrzymane wiadomości"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Rozmowy priorytetowe"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Ostatnie rozmowy"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Zobacz ostatnie wiadomości, nieodebrane połączenia i stany"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Rozmowa"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Wstrzymane przez tryb Nie przeszkadzać"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> wysyła wiadomość"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> wysyła zdjęcie"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem z odczytaniem pomiaru wykorzystania baterii"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 1d7ba07..aa3d628 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toque em uma conversa para adicioná-la à tela inicial"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Volte aqui quando receber mensagens"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversas prioritárias"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
     <string name="okay" msgid="6490552955618608554">"Ok"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e89aab3..22b2eb0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toque numa conversa para a adicionar ao ecrã principal"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Volte aqui quando tiver mensagens"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversas com prioridade"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Veja mensagens recentes, chamadas não atendidas e atualizações de estado"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Colocado em pausa pelo modo Não incomodar"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ocorreu um problema ao ler o medidor da bateria"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 1d7ba07..aa3d628 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgets de conversa"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Toque em uma conversa para adicioná-la à tela inicial"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Volte aqui quando receber mensagens"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversas prioritárias"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
     <string name="okay" msgid="6490552955618608554">"Ok"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 377af78..35a976a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1121,8 +1121,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Deschideți conversația"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgeturi pentru conversație"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Atingeți o conversație ca să o adăugați pe ecranul de pornire"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Reveniți aici după ce primiți câteva mesaje"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversații cu prioritate"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversații recente"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1151,7 +1150,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Vedeți mesaje recente, apeluri pierdute și actualizări de stare"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Conversație"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Întrerupt de Nu deranja"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> a trimis un mesaj"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o imagine"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problemă la citirea măsurării bateriei"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f9bc9b2..ec07b3c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Виджеты чатов"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Нажмите на чат, чтобы добавить его на главный экран"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Здесь вы увидите свои сообщения."</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Важные разговоры"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Недавние разговоры"</string>
     <string name="okay" msgid="6490552955618608554">"ОК"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Будьте в курсе последних сообщений, пропущенных вызовов и обновлений статуса."</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Чат"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Приостановлено в режиме \"Не беспокоить\""</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил сообщение"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил изображение"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удается получить данные об уровне заряда батареи"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0339baa..e81c661 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"සංවාදය විවෘත කරන්න"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"සංවාද විජට්"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ඔබගේ මුල් තිරයට එය එක් කිරීමට සංවාදයක් තට්ටු කරන්න"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"ඔබට පණිවිඩ කිහිපයක් ලැබුණු පසු නැවත මෙහි පරීක්ෂා කරන්න"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ප්‍රමුඛතා සංවාද"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"මෑත සංවාද"</string>
     <string name="okay" msgid="6490552955618608554">"හරි"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"මෑත පණිවිඩ, මඟ හැරුණු ඇමතුම් සහ තත්ත්ව යාවත්කාලීන කිරීම් බලන්න"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"සංවාදය"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"බාධා නොකිරීම මගින් විරාම කර ඇත"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> පණිවිඩයක් එවා ඇත"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> රූපයක් යවන ලදී"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ඔබගේ බැටරි මනුව කියවීමේ දෝෂයකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b0d8d3b..3b2d174 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Miniaplikácie konverzácií"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Klepnite na konverzáciu a pridajte ju tak na plochu"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Vráťte sa sem, až dostanete nejaké správy"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioritné konverzácie"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nedávne konverzácie"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Pozrite si nedávne správy, zmeškané hovory a aktualizácie stavu"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Konverzácia"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pozastavené režimom bez vyrušení"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) správu"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) obrázok"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pri čítaní meradla batérie sa vyskytol problém"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 9d84910..b21b342 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -749,8 +749,8 @@
     <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stanje:&lt;/b&gt; Uvrščeno nižje"</string>
     <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Prikaz na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu"</string>
     <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu."</string>
-    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikaz na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string>
-    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string>
+    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikaz na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavitve"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prednostno"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij."</string>
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Pripomočki za pogovore"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Dotaknite se pogovora, da ga dodate na začetni zaslon."</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Znova preverite tukaj, ko boste prejeli kakšno sporočilo."</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prednostni pogovori"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Nedavni pogovori"</string>
     <string name="okay" msgid="6490552955618608554">"V redu"</string>
@@ -1157,7 +1156,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Več kot <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Ogled nedavnih sporočil, neodgovorjenih klicev in posodobitev stanj"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Pogovor"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"To je začasno zaustavil način »ne moti«."</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sporočilo."</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sliko."</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Težava z branjem indikatorja stanja napolnjenosti baterije"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 78ab1fa..dda9b6c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Miniaplikacionet e bisedave"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Trokit te një bisedë dhe shtoje në ekranin bazë"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Kontrollo përsëri këtu pasi të marrësh disa mesazhe"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Bisedat me përparësi"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Bisedat e fundit"</string>
     <string name="okay" msgid="6490552955618608554">"Në rregull"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Mbi <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Shiko mesazhet e fundit, telefonatat e humbura dhe përditësimet e statusit"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Biseda"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Vendosur në pauzë nga \"Mos shqetëso\""</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një mesazh"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një imazh"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem me leximin e matësit të baterisë"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index d14854b..4a95efb 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1121,8 +1121,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Виџети за конверзацију"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Додирните конверзацију да бисте је додали на почетни екран"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Вратите се овде када добијете неку поруку"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Приоритетне конверзације"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Недавне конверзације"</string>
     <string name="okay" msgid="6490552955618608554">"Важи"</string>
@@ -1151,7 +1150,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Погледајте недавне поруке, пропуштене позиве и ажурирања статуса"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Конверзација"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Паузирано режимом Не узнемиравај"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> шаље поруку"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> шаље слику"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 708b938..322efd8 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Konversationswidgetar"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Tryck på en konversation för att lägga till den på startskärmen"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Besök den här sidan igen när du har fått meddelanden"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Prioriterade konversationer"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Senaste konversationerna"</string>
     <string name="okay" msgid="6490552955618608554">"Okej"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"över <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Se de senaste meddelandena, missade samtal och statusuppdateringar"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Konversation"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Pausad av Stör ej"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> skickade ett meddelande"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> skickade en bild"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batteriindikatorn visas inte"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index f9f2ca3..36d7189 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Wijeti za mazungumzo"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Gusa mazungumzo ili uyaweke kwenye Skrini yako ya kwanza"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Angalia hapa tena utakapopokea ujumbe"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Mazungumzo yenye kipaumbele"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Mazungumzo ya hivi majuzi"</string>
     <string name="okay" msgid="6490552955618608554">"Sawa"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Angalia ujumbe wa hivi majuzi, simu ambazo hukujibu na taarifa za hali"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Mazungumzo"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Imesimamishwa na kipengele cha Usinisumbue"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ametuma ujumbe"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ametuma picha"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Tatizo la kusoma mita ya betri yako"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0ec1d1f..44d9441 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -137,10 +137,10 @@
     <string name="accessibility_phone_button" msgid="4256353121703100427">"ஃபோன்"</string>
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"குரல் உதவி"</string>
     <string name="accessibility_wallet_button" msgid="1458258783460555507">"வாலட்"</string>
-    <string name="accessibility_unlock_button" msgid="122785427241471085">"அன்லாக் செய்"</string>
+    <string name="accessibility_unlock_button" msgid="122785427241471085">"திற"</string>
     <string name="accessibility_lock_icon" msgid="661492842417875775">"சாதனம் பூட்டப்பட்டுள்ளது"</string>
     <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"கைரேகைக்காகக் காத்திருக்கிறது"</string>
-    <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"உங்கள் கைரேகையைப் பயன்படுத்தாமல் அன்லாக் செய்யுங்கள்"</string>
+    <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"உங்கள் கைரேகையைப் பயன்படுத்தாமல் திறக்கவும்"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"முகத்தை ஸ்கேன் செய்கிறது"</string>
     <string name="accessibility_send_smart_reply" msgid="8885032190442015141">"அனுப்பு"</string>
     <string name="accessibility_manage_notification" msgid="582215815790143983">"அறிவிப்புகளை நிர்வகிக்கும் பட்டன்"</string>
@@ -586,10 +586,10 @@
     <string name="monitoring_description_app_work" msgid="3713084153786663662">"உங்கள் பணிக் கணக்கை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. மின்னஞ்சல்கள், ஆப்ஸ், இணையதளங்கள் உட்பட உங்கள் பணி நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION">%2$s</xliff:g> உடன் அது இணைக்கப்பட்டுள்ளது.\n\nமேலும் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"உங்கள் பணிக் கணக்கை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. மின்னஞ்சல்கள், ஆப்ஸ், இணையதளங்கள் உட்பட உங்கள் பணி நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் அது இணைக்கப்பட்டுள்ளது.\n\nஉங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடனும் இணைக்கப்பட்டுள்ளீர்கள்."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent இதைத் திறந்தே வைத்துள்ளது"</string>
-    <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"நீங்கள் கைமுறையாக அன்லாக் செய்யும் வரை, சாதனம் பூட்டப்பட்டிருக்கும்"</string>
+    <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"நீங்கள் கைமுறையாகத் திறக்கும் வரை, சாதனம் பூட்டப்பட்டிருக்கும்"</string>
     <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"விரைவாக அறிவிப்புகளைப் பெறுதல்"</string>
-    <string name="hidden_notifications_text" msgid="5899627470450792578">"அன்லாக் செய்யும் முன் அவற்றைப் பார்க்கவும்"</string>
+    <string name="hidden_notifications_text" msgid="5899627470450792578">"திறக்கும் முன் அவற்றைப் பார்க்கவும்"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"வேண்டாம்"</string>
     <string name="hidden_notifications_setup" msgid="2064795578526982467">"அமை"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"திறந்தநிலை உரையாடல்"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"உரையாடல் விட்ஜெட்டுகள்"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"ஓர் உரையாடலை உங்கள் முகப்புத் திரையில் சேர்க்க அந்த உரையாடலைத் தட்டுங்கள்"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"செய்திகளைப் பெற்றதும் இங்கே மீண்டும் வரவும்"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"முன்னுரிமை அளிக்கப்பட்ட உரையாடல்கள்"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"சமீபத்திய உரையாடல்கள்"</string>
     <string name="okay" msgid="6490552955618608554">"சரி"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"சமீபத்திய மெசேஜ்களையும் தவறிய அழைப்புகளையும் ஸ்டேட்டஸ் அப்டேட்களையும் பார்க்கலாம்"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"உரையாடல்"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"தொந்தரவு செய்ய வேண்டாம் அம்சத்தால் இடைநிறுத்தப்பட்டது"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு மெசேஜ் அனுப்பியுள்ளார்"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு படம் அனுப்பியுள்ளார்"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"பேட்டரி அளவை அறிவதில் சிக்கல்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 48dbe37..8df60b2 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"సంభాషణను తెరవండి"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"సంభాషణ విడ్జెట్‌లు"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"దీనిని మీ మొదటి స్క్రీన్‌కు జోడించడానికి సంభాషణను ట్యాప్ చేయండి"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"మీరు కొన్ని మెసేజ్‌లను పొందిన తర్వాత తిరిగి ఇక్కడ చెక్ చేయండి"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ప్రాధాన్య సంభాషణలు"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"ఇటీవలి సంభాషణలు"</string>
     <string name="okay" msgid="6490552955618608554">"సరే"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్‌లు, మిస్డ్ కాల్‌లు, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్‌ను పంపారు"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ఇమేజ్‌ను పంపారు"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"మీ బ్యాటరీ మీటర్‌ను చదవడంలో సమస్య"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 64b2113..38d2e94 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -438,7 +438,7 @@
     <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"สลับภาพรวม"</string>
     <string name="expanded_header_battery_charged" msgid="5307907517976548448">"ชาร์จแล้ว"</string>
     <string name="expanded_header_battery_charging" msgid="1717522253171025549">"กำลังชาร์จ"</string>
-    <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จะเต็ม"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จึงจะเต็ม"</string>
     <string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ไม่ได้ชาร์จ"</string>
     <string name="ssl_ca_cert_warning" msgid="8373011375250324005">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
     <string name="description_target_search" msgid="3875069993128855865">"ค้นหา"</string>
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"วิดเจ็ตการสนทนา"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"แตะการสนทนาเพื่อเพิ่มไปยังหน้าจอหลัก"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"กลับมาดูที่นี่อีกครั้งเมื่อได้รับข้อความ"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"การสนทนาสำคัญ"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"การสนทนาล่าสุด"</string>
     <string name="okay" msgid="6490552955618608554">"ตกลง"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"ดูข้อความล่าสุด สายที่ไม่ได้รับ และการอัปเดตสถานะ"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"การสนทนา"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"หยุดชั่วคราวโดยฟีเจอร์ห้ามรบกวน"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> ส่งข้อความ"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ส่งรูปภาพ"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"พบปัญหาในการอ่านเครื่องวัดแบตเตอรี่"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7b4a4d1..4e54a52 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Mga widget ng pag-uusap"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Mag-tap sa isang pag-uusap para idagdag ito sa iyong Home screen"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Bumalik dito kapag nakakuha ka na ng ilang mensahe"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Mga priyoridad na pag-uusap"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Mga kamakailang pag-uusap"</string>
     <string name="okay" msgid="6490552955618608554">"Okay"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Tingnan ang mga kamakailang mensahe, hindi nasagot na tawag, at update sa status"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Pag-uusap"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Na-pause ng Huwag Istorbohin"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng mensahe"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng larawan"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nagkaproblema sa pagbabasa ng iyong battery meter"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index fba8b30..2e9784f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Görüşme widget\'ları"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Ana ekranınıza eklemek için bir ileti dizisine dokunun"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Birkaç mesaj aldıktan sonra burayı tekrar kontrol edin"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Öncelikli görüşmeler"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Son görüşmeler"</string>
     <string name="okay" msgid="6490552955618608554">"Tamam"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Yeni mesajları, cevapsız aramaları ve durum güncellemelerini görün"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Görüşme"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> bir mesaj gönderdi"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> bir resim gönderdi"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pil ölçeriniz okunurken sorun oluştu"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b80ed19..9805da3 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -750,7 +750,7 @@
     <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані"</string>
     <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, показується у вигляді спливаючої підказки"</string>
     <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, показується навіть у режимі \"Не турбувати\""</string>
-    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, відображається як спливаючий чат, перериває режим \"Не турбувати\""</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, відображається у вигляді спливаючої підказки, показується навіть у режимі \"Не турбувати\""</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
@@ -1127,8 +1127,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Відкрита розмова"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Віджети розмов"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Натисніть розмову, щоб додати її на головний екран"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Поверніться сюди, коли отримаєте повідомлення"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Важливі розмови"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Нещодавні розмови"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 2288383..a28cedc5 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"گفتگو ویجیٹس"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"اسے اپنے ہوم اسکرین پر شامل کرنے کے لیے گفتگو پر تھپتھپائیں"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"کچھ پیغامات حاصل کرنے کے بعد یہاں دوبارہ چیک کریں"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"ترجیحی گفتگوئیں"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"حالیہ گفتگوئیں"</string>
     <string name="okay" msgid="6490552955618608554">"ٹھیک ہے"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"حالیہ پیغامات، چھوٹی ہوئی کالز اور اسٹیٹس اپ ڈیٹس دیکھیں"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"گفتگو"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"\'ڈسٹرب نہ کریں\' کے ذریعے موقوف کیا گیا"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک پیغام بھیجا"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک تصویر بھیجی"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0c1d6c6..3263ae9 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Suhbat vidjetlari"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Bosh ekranga chiqariladigan suhbat ustiga bosing"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Oxirgi suhbatlaringiz shu yerda chiqadi"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"Keyinroq bu yerda ayrim xabarlar chiqadi"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Muhim suhbatlar"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Oxirgi suhbatlar"</string>
     <string name="okay" msgid="6490552955618608554">"OK"</string>
@@ -1144,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Oxirgi xabarlar, javobsiz chaqiruvlar va holat yangilanishlari"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Suhbat"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Bezovta qilinmasin rejimi pauza qildi"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> xabar yubordi"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> rasm yubordi"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya quvvati aniqlanmadi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 96ea6df..28bb507 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Tiện ích trò chuyện"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Nhấn vào một cuộc trò chuyện để thêm cuộc trò chuyện đó vào Màn hình chính"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Hãy quay lại đây khi bạn nhận được tin nhắn"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Cuộc trò chuyện ưu tiên"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Cuộc trò chuyện gần đây"</string>
     <string name="okay" msgid="6490552955618608554">"Ok"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Hơn <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Xem các tin nhắn, cuộc gọi nhỡ và thông tin cập nhật trạng thái gần đây"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Cuộc trò chuyện"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Đã tạm dừng do chế độ Không làm phiền"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một tin nhắn"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một hình ảnh"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ebffe95..c773332 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"对话微件"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"点按对话即可将其添加到主屏幕"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"请在收到一些消息后再回来查看"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"优先对话"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"近期对话"</string>
     <string name="okay" msgid="6490552955618608554">"确定"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"查看近期的消息、未接电话和状态更新"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"对话"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"勿扰模式已暂停通知"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>发送了一条消息"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>发送了一张图片"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7f2edd9..0eeb4bb 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1115,7 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"對話小工具"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"輕按對話即可新增至主畫面"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"您最近的對話會在這裡顯示"</string>
+    <string name="no_conversations_text" msgid="7362374212649891057">"等你收到一些訊息後再回來查看吧"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"優先對話"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"最近的對話"</string>
     <string name="okay" msgid="6490552955618608554">"確定"</string>
@@ -1144,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"「請勿騷擾」已暫停通知"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>傳送了訊息"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了圖片"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 53a281e..100a87c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"開放式對話"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"對話小工具"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"輕觸對話即可新增至主畫面"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"等你收到一些訊息後再回來這裡看看"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"優先對話"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"最近的對話"</string>
     <string name="okay" msgid="6490552955618608554">"確定"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"零打擾模式已將通知暫停"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一則訊息"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一張圖片"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 76df48a..30eecaf 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1115,8 +1115,7 @@
     <string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Amawijethi wengxoxo"</string>
     <string name="select_conversation_text" msgid="3376048251434956013">"Thepha ingxoxo ukuyengeza Kusikrini sakho sasekhaya"</string>
-    <!-- no translation found for no_conversations_text (5354115541282395015) -->
-    <skip />
+    <string name="no_conversations_text" msgid="7362374212649891057">"Phinda uhlole futhi lapho uthola imilayezo ethile"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Izingxoxo ezibalulekile"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Izingxoxo zakamuva"</string>
     <string name="okay" msgid="6490552955618608554">"Kulungile"</string>
@@ -1145,7 +1144,8 @@
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
     <string name="people_tile_description" msgid="8154966188085545556">"Bona imiyalezo yakamuva, amakholi akuphuthile, nezibuyekezo zesimo"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"Ingxoxo"</string>
-    <string name="paused_by_dnd" msgid="7856941866433556428">"Kumiswe okuthi Ungaphazamisi"</string>
+    <!-- no translation found for paused_by_dnd (7856941866433556428) -->
+    <skip />
     <string name="new_notification_text_content_description" msgid="5574393603145263727">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele umlayezo"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele isithombe"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kube khona inkinga ngokufunda imitha yakho yebhethri"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2a1bee5..7d37445 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -602,8 +602,6 @@
 
     <!-- Whether wallet view is shown in landscape / seascape orientations -->
     <bool name="global_actions_show_landscape_wallet_view">false</bool>
-    <!-- Whether global actions should show an informational message about changes in S -->
-    <bool name="global_actions_show_change_info">false</bool>
 
     <!-- Package name of the preferred system app to perform eSOS action -->
     <string name="config_preferredEmergencySosPackage" translatable="false"></string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a526803..8bac447 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1117,7 +1117,6 @@
     <dimen name="global_actions_button_padding">38dp</dimen>
     <dimen name="global_actions_corner_radius">28dp</dimen>
     <dimen name="global_actions_lite_padding">24dp</dimen>
-    <dimen name="global_actions_info_margin">32dp</dimen>
 
     <!-- The maximum offset in either direction that elements are moved horizontally to prevent
          burn-in on AOD. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bc1c67c..50e3834 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2980,9 +2980,4 @@
 
     <!-- Content description for a chip in the status bar showing that the user is currently on a phone call. [CHAR LIMIT=NONE] -->
     <string name="ongoing_phone_call_content_description">Ongoing phone call</string>
-
-    <!-- Placeholder for string describing changes in global actions -->
-    <string name="global_actions_change_description" translatable="false"><xliff:g>%1$s</xliff:g></string>
-    <!-- URL for more information about changes in global actions -->
-    <string name="global_actions_change_url" translatable="false"></string>
 </resources>
diff --git a/packages/SystemUI/shared/lint-baseline.xml b/packages/SystemUI/shared/lint-baseline.xml
index ec9d8fd..4bd6729 100644
--- a/packages/SystemUI/shared/lint-baseline.xml
+++ b/packages/SystemUI/shared/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev">
 
     <issue
         id="NewApi"
@@ -300,6 +300,17 @@
 
     <issue
         id="NewApi"
+        message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`"
+        errorLine1="        taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;"
+        errorLine2="                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
+            line="192"
+            column="49"/>
+    </issue>
+
+    <issue
+        id="NewApi"
         message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#isRunning`"
         errorLine1="            isNotInRecents = !change.getTaskInfo().isRunning;"
         errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -311,6 +322,17 @@
 
     <issue
         id="NewApi"
+        message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#isRunning`"
+        errorLine1="            isNotInRecents = !change.getTaskInfo().isRunning;"
+        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
+            line="210"
+            column="31"/>
+    </issue>
+
+    <issue
+        id="NewApi"
         message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#release`"
         errorLine1="        leash.mSurfaceControl.release();"
         errorLine2="                              ~~~~~~~">
@@ -575,6 +597,17 @@
 
     <issue
         id="NewApi"
+        message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`"
+        errorLine1="        onTaskMovedToFront(taskInfo.taskId);"
+        errorLine2="                           ~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java"
+            line="70"
+            column="28"/>
+    </issue>
+
+    <issue
+        id="NewApi"
         message="Call requires API level 29 (current min is 26): `android.graphics.Bitmap#wrapHardwareBuffer`"
         errorLine1="                thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 277b2e3..de9558e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -77,8 +77,17 @@
     void onSplitScreenSecondaryBoundsChanged(in Rect bounds, in Rect insets) = 17;
 
     /**
-     * Sent IME status changes
+     * Sent when suggested rotation button could be shown
      */
-    void onImeWindowStatusChanged(int displayId, IBinder token, int vis, int backDisposition,
-                         boolean showImeSwitcher) = 18;
+    void onRotationProposal(int rotation, boolean isValid) = 18;
+
+    /**
+     * Sent when disable flags change
+     */
+    void disable(int displayId, int state1, int state2, boolean animate) = 19;
+
+    /**
+     * Sent when behavior changes. See WindowInsetsController#@Behavior
+     */
+    void onSystemBarAttributesChanged(int displayId, int behavior) = 20;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 7dffc26..a624f061 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -16,9 +16,14 @@
 
 package com.android.systemui.shared.recents.utilities;
 
+import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+
 import android.graphics.Color;
+import android.inputmethodservice.InputMethodService;
 import android.os.Handler;
 import android.os.Message;
+import android.view.Surface;
 
 /* Common code */
 public class Utilities {
@@ -31,6 +36,23 @@
         h.sendMessageAtFrontOfQueue(msg);
     }
 
+    public static boolean isRotationAnimationCCW(int from, int to) {
+        // All 180deg WM rotation animations are CCW, match that
+        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false;
+        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW
+        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true;
+        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true;
+        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false;
+        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW
+        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW
+        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true;
+        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false;
+        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false;
+        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW
+        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true;
+        return false; // Default
+    }
+
     /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
     public static float computeContrastBetweenColors(int bg, int fg) {
         float bgR = Color.red(bg) / 255f;
@@ -58,4 +80,34 @@
     public static float clamp(float value, float min, float max) {
         return Math.max(min, Math.min(max, value));
     }
+
+    /**
+     * @return updated set of flags from InputMethodService based off {@param oldHints}
+     *          Leaves original hints unmodified
+     */
+    public static int calculateBackDispositionHints(int oldHints, int backDisposition,
+            boolean imeShown, boolean showImeSwitcher) {
+        int hints = oldHints;
+        switch (backDisposition) {
+            case InputMethodService.BACK_DISPOSITION_DEFAULT:
+            case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
+            case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
+                if (imeShown) {
+                    hints |= NAVIGATION_HINT_BACK_ALT;
+                } else {
+                    hints &= ~NAVIGATION_HINT_BACK_ALT;
+                }
+                break;
+            case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
+                hints &= ~NAVIGATION_HINT_BACK_ALT;
+                break;
+        }
+        if (showImeSwitcher) {
+            hints |= NAVIGATION_HINT_IME_SHOWN;
+        } else {
+            hints &= ~NAVIGATION_HINT_IME_SHOWN;
+        }
+
+        return hints;
+    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/ViewRippler.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/ViewRippler.java
new file mode 100644
index 0000000..5581a1c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/ViewRippler.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.android.systemui.shared.recents.utilities;
+
+import android.view.View;
+
+/**
+ * Shows view ripples by toggling the provided Views "pressed" state.
+ * Ripples 4 times.
+ */
+public class ViewRippler {
+    private static final int RIPPLE_OFFSET_MS = 50;
+    private static final int RIPPLE_INTERVAL_MS = 2000;
+    private View mRoot;
+
+    public void start(View root) {
+        stop(); // Stop any pending ripple animations
+
+        mRoot = root;
+
+        // Schedule pending ripples, offset the 1st to avoid problems with visibility change
+        mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
+        mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
+        mRoot.postOnAnimationDelayed(mRipple, 2 * RIPPLE_INTERVAL_MS);
+        mRoot.postOnAnimationDelayed(mRipple, 3 * RIPPLE_INTERVAL_MS);
+        mRoot.postOnAnimationDelayed(mRipple, 4 * RIPPLE_INTERVAL_MS);
+    }
+
+    public void stop() {
+        if (mRoot != null) mRoot.removeCallbacks(mRipple);
+    }
+
+    private final Runnable mRipple = new Runnable() {
+        @Override
+        public void run() { // Cause the ripple to fire via false presses
+            if (!mRoot.isAttachedToWindow()) return;
+            mRoot.setPressed(true /* pressed */);
+            mRoot.setPressed(false /* pressed */);
+        }
+    };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index c468e41..4663a9a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -112,6 +112,10 @@
     public static final int SYSUI_STATE_IME_SHOWING = 1 << 18;
     // The window magnification is overlapped with system gesture insets at the bottom.
     public static final int SYSUI_STATE_MAGNIFICATION_OVERLAP = 1 << 19;
+    // ImeSwitcher is showing
+    public static final int SYSUI_STATE_IME_SWITCHER_SHOWING = 1 << 20;
+    // Device dozing/AOD state
+    public static final int SYSUI_STATE_DEVICE_DOZING = 1 << 21;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -133,7 +137,9 @@
             SYSUI_STATE_ONE_HANDED_ACTIVE,
             SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
             SYSUI_STATE_IME_SHOWING,
-            SYSUI_STATE_MAGNIFICATION_OVERLAP
+            SYSUI_STATE_MAGNIFICATION_OVERLAP,
+            SYSUI_STATE_IME_SWITCHER_SHOWING,
+            SYSUI_STATE_DEVICE_DOZING
     })
     public @interface SystemUiStateFlags {}
 
@@ -162,6 +168,8 @@
                 ? "allow_gesture" : "");
         str.add((flags & SYSUI_STATE_IME_SHOWING) != 0 ? "ime_visible" : "");
         str.add((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0 ? "magnification_overlap" : "");
+        str.add((flags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0 ? "ime_switcher_showing" : "");
+        str.add((flags & SYSUI_STATE_DEVICE_DOZING) != 0 ? "device_dozing" : "");
         return str.toString();
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index ee55bf0..fdd1abe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -260,7 +260,7 @@
                                 t.remove(leashMap.valueAt(i));
                             }
                             t.apply();
-                            finishCallback.onTransitionFinished(null /* wct */);
+                            finishCallback.onTransitionFinished(null /* wct */, null /* sct */);
                         } catch (RemoteException e) {
                             Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
                                     + " finished callback", e);
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 653d730..a77cc87 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
@@ -17,14 +17,17 @@
 package com.android.systemui.shared.system;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionFilter.CONTAINER_ORDER_TOP;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.app.ActivityTaskManager;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.Parcelable;
@@ -73,7 +76,7 @@
                     IRemoteTransitionFinishedCallback finishedCallback) {
                 final Runnable finishAdapter = () ->  {
                     try {
-                        finishedCallback.onTransitionFinished(null /* wct */);
+                        finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to call transition finished callback", e);
                     }
@@ -87,7 +90,7 @@
                     IRemoteTransitionFinishedCallback finishedCallback) {
                 final Runnable finishAdapter = () ->  {
                     try {
-                        finishedCallback.onTransitionFinished(null /* wct */);
+                        finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to call transition finished callback", e);
                     }
@@ -119,6 +122,7 @@
                 // This transition is for opening recents, so recents is on-top. We want to draw
                 // the current going-away task on top of recents, though, so move it to front
                 WindowContainerToken pausingTask = null;
+                SurfaceControl pausingLeash = null;
                 for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                     final TransitionInfo.Change change = info.getChanges().get(i);
                     if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) {
@@ -135,7 +139,7 @@
                 }
                 t.apply();
                 mRecentsSession.setup(controller, info, finishedCallback, pausingTask,
-                        leashMap);
+                        leashMap, mToken);
                 recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
                         new Rect());
             }
@@ -147,7 +151,7 @@
                 if (!mergeTarget.equals(mToken)) return;
                 if (!mRecentsSession.merge(info, t, recents)) return;
                 try {
-                    finishedCallback.onTransitionFinished(null /* wct */);
+                    finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error merging transition.", e);
                 }
@@ -161,9 +165,13 @@
             mFilter = new TransitionFilter();
         }
         mFilter.mRequirements =
-                new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
+                new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(),
+                        new TransitionFilter.Requirement()};
         mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME;
         mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+        mFilter.mRequirements[0].mOrder = CONTAINER_ORDER_TOP;
+        mFilter.mRequirements[1].mActivityType = ACTIVITY_TYPE_STANDARD;
+        mFilter.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
     }
 
     /**
@@ -178,10 +186,11 @@
         private TransitionInfo mInfo = null;
         private SurfaceControl mOpeningLeash = null;
         private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
+        private IBinder mTransition = null;
 
         void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
                 IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
-                ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
+                ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
             if (mInfo != null) {
                 throw new IllegalStateException("Trying to run a new recents animation while"
                         + " recents is already active.");
@@ -191,6 +200,7 @@
             mFinishCB = finishCB;
             mPausingTask = pausingTask;
             mLeashMap = leashMap;
+            mTransition = transition;
         }
 
         @SuppressLint("NewApi")
@@ -263,10 +273,13 @@
             try {
                 if (!toHome && mPausingTask != null && mOpeningLeash == null) {
                     // The gesture went back to opening the app rather than continuing with
-                    // recents, so end the transition by moving the app back to the top.
+                    // recents, so end the transition by moving the app back to the top (and also
+                    // re-showing it's task).
                     final WindowContainerTransaction wct = new WindowContainerTransaction();
                     wct.reorder(mPausingTask, true /* onTop */);
-                    mFinishCB.onTransitionFinished(wct);
+                    final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+                    t.show(mInfo.getChange(mPausingTask).getLeash());
+                    mFinishCB.onTransitionFinished(wct, t);
                 } else {
                     if (mOpeningLeash != null) {
                         // TODO: the launcher animation should handle this
@@ -275,7 +288,7 @@
                         t.setAlpha(mOpeningLeash, 1.f);
                         t.apply();
                     }
-                    mFinishCB.onTransitionFinished(null /* wct */);
+                    mFinishCB.onTransitionFinished(null /* wct */, null /* sct */);
                 }
             } catch (RemoteException e) {
                 Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
@@ -298,6 +311,7 @@
             mInfo = null;
             mOpeningLeash = null;
             mLeashMap = null;
+            mTransition = null;
         }
 
         @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
@@ -318,6 +332,23 @@
         @Override public boolean removeTask(int taskId) {
             return mWrapped != null ? mWrapped.removeTask(taskId) : false;
         }
+
+        /**
+         * @see IRecentsAnimationController#detachNavigationBarFromApp
+         */
+        @Override public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+            try {
+                ActivityTaskManager.getService().detachNavigationBarFromApp(mTransition);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to detach the navigation bar from app", e);
+            }
+        }
+
+        /**
+         * @see IRecentsAnimationController#animateNavigationBarToApp(long)
+         */
+        @Override public void animateNavigationBarToApp(long duration) {
+        }
     }
 
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
index 2d01d6a..e49d9f9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
@@ -16,6 +16,4 @@
 
 package com.android.systemui.shared.system.smartspace;
 
-import com.android.systemui.shared.system.smartspace.SmartspaceState;
-
-parcelable SmartspaceState;
\ No newline at end of file
+parcelable SmartspaceState;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ef052c4..0bd9ca4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -14,6 +14,9 @@
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
 import com.android.systemui.R;
@@ -22,6 +25,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.TimeZone;
 
@@ -37,6 +42,13 @@
     private static final long CLOCK_IN_MILLIS = 200;
     private static final long SMARTSPACE_MOVE_MILLIS = 350;
 
+    @IntDef({LARGE, SMALL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ClockSize { }
+
+    public static final int LARGE = 0;
+    public static final int SMALL = 1;
+
     /**
      * Optional/alternative clock injected via plugin.
      */
@@ -64,13 +76,13 @@
     private float mDarkAmount;
 
     /**
-     * Boolean value indicating if notifications are visible on lock screen. Use null to signify
-     * it is uninitialized.
+     * Indicates which clock is currently displayed - should be one of {@link ClockSize}.
+     * Use null to signify it is uninitialized.
      */
-    private Boolean mHasVisibleNotifications = null;
+    @ClockSize private Integer mDisplayedClockSize = null;
 
-    private AnimatorSet mClockInAnim = null;
-    private AnimatorSet mClockOutAnim = null;
+    @VisibleForTesting AnimatorSet mClockInAnim = null;
+    @VisibleForTesting AnimatorSet mClockOutAnim = null;
     private ObjectAnimator mSmartspaceAnim = null;
 
     /**
@@ -260,19 +272,17 @@
     }
 
     /**
-     * Based upon whether notifications are showing or not, display/hide the large clock and
-     * the smaller version.
+     * Display the desired clock and hide the other one
+     *
+     * @return true if desired clock appeared and false if it was already visible
      */
-    boolean willSwitchToLargeClock(boolean hasVisibleNotifications) {
-        if (mHasVisibleNotifications != null
-                && hasVisibleNotifications == mHasVisibleNotifications) {
+    boolean switchToClock(@ClockSize int clockSize) {
+        if (mDisplayedClockSize != null && clockSize == mDisplayedClockSize) {
             return false;
         }
-        boolean useLargeClock = !hasVisibleNotifications;
-        animateClockChange(useLargeClock);
-
-        mHasVisibleNotifications = hasVisibleNotifications;
-        return useLargeClock;
+        animateClockChange(clockSize == LARGE);
+        mDisplayedClockSize = clockSize;
+        return true;
     }
 
     public Paint getPaint() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index a28d174..9dcbda9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -19,6 +19,8 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static com.android.keyguard.KeyguardClockSwitch.LARGE;
+
 import android.app.WallpaperManager;
 import android.content.res.Resources;
 import android.text.TextUtils;
@@ -238,10 +240,12 @@
     }
 
     /**
-     * Set whether or not the lock screen is showing notifications.
+     * Set which clock should be displayed on the keyguard. The other one will be automatically
+     * hidden.
      */
-    public void setHasVisibleNotifications(boolean hasVisibleNotifications) {
-        if (mView.willSwitchToLargeClock(hasVisibleNotifications)) {
+    public void displayClock(@KeyguardClockSwitch.ClockSize int clockSize) {
+        boolean appeared = mView.switchToClock(clockSize);
+        if (appeared && clockSize == LARGE) {
             mLargeClockViewController.animateAppear();
         }
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index ca4d73b..840e8c8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -42,7 +42,6 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.dynamicanimation.animation.DynamicAnimation;
 import androidx.dynamicanimation.animation.SpringAnimation;
@@ -104,7 +103,6 @@
 
     private boolean mIsSecurityViewLeftAligned = true;
     private boolean mOneHandedMode = false;
-    private SecurityMode mSecurityMode = SecurityMode.Invalid;
     private ViewPropertyAnimator mRunningOneHandedAnimator;
 
     private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
@@ -248,66 +246,47 @@
     }
 
     void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
-        mSecurityMode = securityMode;
         mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
         updateBiometricRetry(securityMode, faceAuthEnabled);
-
-        updateLayoutForSecurityMode(securityMode);
     }
 
-    void updateLayoutForSecurityMode(SecurityMode securityMode) {
-        mSecurityMode = securityMode;
-        mOneHandedMode = canUseOneHandedBouncer();
-
-        if (mOneHandedMode) {
-            mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext);
-        }
-
+    /**
+     * Sets whether this security container is in one handed mode. If so, it will measure its
+     * child SecurityViewFlipper in one half of the screen, and move it when tapping on the opposite
+     * side of the screen.
+     */
+    public void setOneHandedMode(boolean oneHandedMode) {
+        mOneHandedMode = oneHandedMode;
         updateSecurityViewGravity();
         updateSecurityViewLocation(false);
     }
 
-    /** Update keyguard position based on a tapped X coordinate. */
-    public void updateKeyguardPosition(float x) {
-        if (mOneHandedMode) {
-            moveBouncerForXCoordinate(x, /* animate= */false);
-        }
+    /** Returns whether this security container is in one-handed mode. */
+    public boolean isOneHandedMode() {
+        return mOneHandedMode;
     }
 
-    /** Return whether the one-handed keyguard should be enabled. */
-    private boolean canUseOneHandedBouncer() {
-        // Is it enabled?
-        if (!getResources().getBoolean(
-                com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) {
-            return false;
-        }
-
-        if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) {
-            return false;
-        }
-
-        return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
+    /**
+     * When in one-handed mode, sets if the inner SecurityViewFlipper should be aligned to the
+     * left-hand side of the screen or not, and whether to animate when moving between the two.
+     */
+    public void setOneHandedModeLeftAligned(boolean leftAligned, boolean animate) {
+        mIsSecurityViewLeftAligned = leftAligned;
+        updateSecurityViewLocation(animate);
     }
 
-    /** Read whether the one-handed keyguard should be on the left/right from settings. */
-    private boolean isOneHandedKeyguardLeftAligned(Context context) {
-        try {
-            return Settings.Global.getInt(context.getContentResolver(),
-                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
-                    == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
-        } catch (Settings.SettingNotFoundException ex) {
-            return true;
-        }
+    /** Returns whether the inner SecurityViewFlipper is left-aligned when in one-handed mode. */
+    public boolean isOneHandedModeLeftAligned() {
+        return mIsSecurityViewLeftAligned;
     }
 
     private void updateSecurityViewGravity() {
-        View securityView = findKeyguardSecurityView();
-
-        if (securityView == null) {
+        if (mSecurityViewFlipper == null) {
             return;
         }
 
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams();
+        FrameLayout.LayoutParams lp =
+                (FrameLayout.LayoutParams) mSecurityViewFlipper.getLayoutParams();
 
         if (mOneHandedMode) {
             lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
@@ -315,7 +294,7 @@
             lp.gravity = Gravity.CENTER_HORIZONTAL;
         }
 
-        securityView.setLayoutParams(lp);
+        mSecurityViewFlipper.setLayoutParams(lp);
     }
 
     /**
@@ -324,14 +303,12 @@
      * by the security view .
      */
     private void updateSecurityViewLocation(boolean animate) {
-        View securityView = findKeyguardSecurityView();
-
-        if (securityView == null) {
+        if (mSecurityViewFlipper == null) {
             return;
         }
 
         if (!mOneHandedMode) {
-            securityView.setTranslationX(0);
+            mSecurityViewFlipper.setTranslationX(0);
             return;
         }
 
@@ -343,7 +320,8 @@
         int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
 
         if (animate) {
-            mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation);
+            mRunningOneHandedAnimator =
+                    mSecurityViewFlipper.animate().translationX(targetTranslation);
             mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
             mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() {
                 @Override
@@ -355,27 +333,10 @@
             mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
             mRunningOneHandedAnimator.start();
         } else {
-            securityView.setTranslationX(targetTranslation);
+            mSecurityViewFlipper.setTranslationX(targetTranslation);
         }
     }
 
-    @Nullable
-    private KeyguardSecurityViewFlipper findKeyguardSecurityView() {
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-
-            if (isKeyguardSecurityView(child)) {
-                return (KeyguardSecurityViewFlipper) child;
-            }
-        }
-
-        return null;
-    }
-
-    private boolean isKeyguardSecurityView(View view) {
-        return view instanceof KeyguardSecurityViewFlipper;
-    }
-
     public void onPause() {
         if (mAlertDialog != null) {
             mAlertDialog.dismiss();
@@ -635,7 +596,7 @@
         for (int i = 0; i < getChildCount(); i++) {
             final View view = getChildAt(i);
             if (view.getVisibility() != GONE) {
-                if (mOneHandedMode && isKeyguardSecurityView(view)) {
+                if (mOneHandedMode && view == mSecurityViewFlipper) {
                     measureChildWithMargins(view, halfWidthMeasureSpec, 0,
                             heightMeasureSpec, 0);
                 } else {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index fde8213..cb5c6c3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -32,6 +32,7 @@
 import android.content.res.Configuration;
 import android.metrics.LogMaker;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
 import android.view.MotionEvent;
@@ -49,6 +50,8 @@
 import com.android.keyguard.dagger.KeyguardBouncerScope;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Gefingerpoken;
+import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -74,12 +77,14 @@
     private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
     private final SecurityCallback mSecurityCallback;
     private final ConfigurationController mConfigurationController;
+    private final FalsingCollector mFalsingCollector;
 
     private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
 
     private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
 
-    private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
+    @VisibleForTesting
+    final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
         private MotionEvent mTouchDown;
         @Override
         public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -91,6 +96,17 @@
             // Do just a bit of our own falsing. People should only be tapping on the input, not
             // swiping.
             if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                // If we're in one handed mode, the user can tap on the opposite side of the screen
+                // to move the bouncer across. In that case, inhibit the falsing (otherwise the taps
+                // to move the bouncer to each screen side can end up closing it instead).
+                if (mView.isOneHandedMode()) {
+                    if ((mView.isOneHandedModeLeftAligned() && ev.getX() > mView.getWidth() / 2f)
+                            || (!mView.isOneHandedModeLeftAligned()
+                            && ev.getX() <= mView.getWidth() / 2f)) {
+                        mFalsingCollector.avoidGesture();
+                    }
+                }
+
                 if (mTouchDown != null) {
                     mTouchDown.recycle();
                     mTouchDown = null;
@@ -202,7 +218,8 @@
             KeyguardStateController keyguardStateController,
             SecurityCallback securityCallback,
             KeyguardSecurityViewFlipperController securityViewFlipperController,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            FalsingCollector falsingCollector) {
         super(view);
         mLockPatternUtils = lockPatternUtils;
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -216,6 +233,7 @@
                 mKeyguardSecurityCallback);
         mConfigurationController = configurationController;
         mLastOrientation = getResources().getConfiguration().orientation;
+        mFalsingCollector = falsingCollector;
     }
 
     @Override
@@ -440,13 +458,49 @@
         if (newView != null) {
             newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
             mSecurityViewFlipperController.show(newView);
-            mView.updateLayoutForSecurityMode(securityMode);
+            configureOneHandedMode();
         }
 
         mSecurityCallback.onSecurityModeChanged(
                 securityMode, newView != null && newView.needsInput());
     }
 
+    /** Read whether the one-handed keyguard should be on the left/right from settings. */
+    private boolean isOneHandedKeyguardLeftAligned() {
+        try {
+            return Settings.Global.getInt(mView.getContext().getContentResolver(),
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
+                    == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
+        } catch (Settings.SettingNotFoundException ex) {
+            return true;
+        }
+    }
+
+    private boolean canUseOneHandedBouncer() {
+        // Is it enabled?
+        if (!getResources().getBoolean(
+                com.android.internal.R.bool.config_enableDynamicKeyguardPositioning)) {
+            return false;
+        }
+
+        if (!KeyguardSecurityModel.isSecurityViewOneHanded(mCurrentSecurityMode)) {
+            return false;
+        }
+
+        return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
+    }
+
+    private void configureOneHandedMode() {
+        boolean oneHandedMode = canUseOneHandedBouncer();
+
+        mView.setOneHandedMode(oneHandedMode);
+
+        if (oneHandedMode) {
+            mView.setOneHandedModeLeftAligned(
+                    isOneHandedKeyguardLeftAligned(), /* animate= */false);
+        }
+    }
+
     public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
         // +1 for this time
         final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
@@ -511,13 +565,15 @@
         int newOrientation = getResources().getConfiguration().orientation;
         if (newOrientation != mLastOrientation) {
             mLastOrientation = newOrientation;
-            mView.updateLayoutForSecurityMode(mCurrentSecurityMode);
+            configureOneHandedMode();
         }
     }
 
     /** Update keyguard position based on a tapped X coordinate. */
     public void updateKeyguardPosition(float x) {
-        mView.updateKeyguardPosition(x);
+        if (mView.isOneHandedMode()) {
+            mView.setOneHandedModeLeftAligned(x <= mView.getWidth() / 2f, false);
+        }
     }
 
     static class Factory {
@@ -533,6 +589,7 @@
         private final KeyguardStateController mKeyguardStateController;
         private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
         private final ConfigurationController mConfigurationController;
+        private final FalsingCollector mFalsingCollector;
 
         @Inject
         Factory(KeyguardSecurityContainer view,
@@ -545,7 +602,8 @@
                 UiEventLogger uiEventLogger,
                 KeyguardStateController keyguardStateController,
                 KeyguardSecurityViewFlipperController securityViewFlipperController,
-                ConfigurationController configurationController) {
+                ConfigurationController configurationController,
+                FalsingCollector falsingCollector) {
             mView = view;
             mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
             mLockPatternUtils = lockPatternUtils;
@@ -556,6 +614,7 @@
             mKeyguardStateController = keyguardStateController;
             mSecurityViewFlipperController = securityViewFlipperController;
             mConfigurationController = configurationController;
+            mFalsingCollector = falsingCollector;
         }
 
         public KeyguardSecurityContainerController create(
@@ -564,7 +623,7 @@
                     mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
                     mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
                     mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
-                    mConfigurationController);
+                    mConfigurationController, mFalsingCollector);
         }
 
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 2096c31..2158401 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.util.Slog;
 
+import com.android.keyguard.KeyguardClockSwitch.ClockSize;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
@@ -126,10 +127,11 @@
     }
 
     /**
-     * Set whether or not the lock screen is showing notifications.
+     * Set which clock should be displayed on the keyguard. The other one will be automatically
+     * hidden.
      */
-    public void setHasVisibleNotifications(boolean hasVisibleNotifications) {
-        mKeyguardClockSwitchController.setHasVisibleNotifications(hasVisibleNotifications);
+    public void displayClock(@ClockSize int clockSize) {
+        mKeyguardClockSwitchController.displayClock(clockSize);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bd000b2..1344be6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2785,6 +2785,20 @@
         updateBiometricListeningState();
     }
 
+    /** Notifies that the occluded state changed. */
+    public void onKeyguardOccludedChanged(boolean occluded) {
+        Assert.isMainThread();
+        if (DEBUG) {
+            Log.d(TAG, "onKeyguardOccludedChanged(" + occluded + ")");
+        }
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onKeyguardOccludedChanged(occluded);
+            }
+        }
+    }
+
     /**
      * Handle {@link #MSG_KEYGUARD_RESET}
      */
@@ -2967,6 +2981,7 @@
         callback.onPhoneStateChanged(mPhoneState);
         callback.onRefreshCarrierInfo();
         callback.onClockVisibilityChanged();
+        callback.onKeyguardOccludedChanged(mKeyguardOccluded);
         callback.onKeyguardVisibilityChangedRaw(mKeyguardIsVisible);
         callback.onTelephonyCapable(mTelephonyCapable);
         callback.onLockScreenModeChanged(mLockScreenMode);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 9849a7e..6aa7aaa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -88,6 +88,12 @@
      */
     public void onKeyguardVisibilityChanged(boolean showing) { }
 
+    /**
+     * Called when the keyguard occluded state changes.
+     * @param occluded Indicates if the keyguard is now occluded.
+     */
+    public void onKeyguardOccludedChanged(boolean occluded) { }
+
     public void onKeyguardVisibilityChangedRaw(boolean showing) {
         final long now = SystemClock.elapsedRealtime();
         if (showing == mShowing
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 0ae89bc..1d355f2 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -16,25 +16,24 @@
 
 package com.android.systemui;
 
-import android.app.ActivityManager;
-import android.app.Dialog;
+import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.qs.QSUserSwitcherEvent;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.util.settings.SecureSettings;
 
 /**
  * Manages notification when a guest session is resumed.
@@ -43,16 +42,23 @@
 
     private static final String TAG = "GuestResumeSessionReceiver";
 
-    private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
+    @VisibleForTesting
+    public static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
 
-    private Dialog mNewSessionDialog;
+    @VisibleForTesting
+    public AlertDialog mNewSessionDialog;
+    private final UserTracker mUserTracker;
     private final UserSwitcherController mUserSwitcherController;
     private final UiEventLogger mUiEventLogger;
+    private final SecureSettings mSecureSettings;
 
     public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController,
-            UiEventLogger uiEventLogger) {
+            UserTracker userTracker, UiEventLogger uiEventLogger,
+            SecureSettings secureSettings) {
         mUserSwitcherController = userSwitcherController;
+        mUserTracker = userTracker;
         mUiEventLogger = uiEventLogger;
+        mSecureSettings = secureSettings;
     }
 
     /**
@@ -78,26 +84,19 @@
                 return;
             }
 
-            UserInfo currentUser;
-            try {
-                currentUser = ActivityManager.getService().getCurrentUser();
-            } catch (RemoteException e) {
-                return;
-            }
+            UserInfo currentUser = mUserTracker.getUserInfo();
             if (!currentUser.isGuest()) {
                 return;
             }
 
-            ContentResolver cr = context.getContentResolver();
-            int notFirstLogin = Settings.System.getIntForUser(
-                    cr, SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
+            int notFirstLogin = mSecureSettings.getIntForUser(
+                    SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
             if (notFirstLogin != 0) {
                 mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
-                        mUiEventLogger, userId);
+                        mUserTracker, mUiEventLogger, userId);
                 mNewSessionDialog.show();
             } else {
-                Settings.System.putIntForUser(
-                        cr, SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
+                mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
             }
         }
     }
@@ -109,18 +108,27 @@
         }
     }
 
-    private static class ResetSessionDialog extends SystemUIDialog implements
+    /**
+     * Dialog shown when user when asking for confirmation before deleting guest user.
+     */
+    @VisibleForTesting
+    public static class ResetSessionDialog extends SystemUIDialog implements
             DialogInterface.OnClickListener {
 
-        private static final int BUTTON_WIPE = BUTTON_NEGATIVE;
-        private static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
+        @VisibleForTesting
+        public static final int BUTTON_WIPE = BUTTON_NEGATIVE;
+        @VisibleForTesting
+        public static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
 
         private final UserSwitcherController mUserSwitcherController;
         private final UiEventLogger mUiEventLogger;
         private final int mUserId;
 
-        ResetSessionDialog(Context context, UserSwitcherController userSwitcherController,
-                UiEventLogger uiEventLogger, int userId) {
+        ResetSessionDialog(Context context,
+                UserSwitcherController userSwitcherController,
+                UserTracker userTracker,
+                UiEventLogger uiEventLogger,
+                int userId) {
             super(context);
 
             setTitle(context.getString(R.string.guest_wipe_session_title));
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index ca2c034..fa56453 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -161,7 +161,7 @@
         mNotificationShadeController = notificationShadeController;
         // Saving in instance variable since to prevent GC since
         // NotificationShadeWindowController.registerCallback() only keeps weak references.
-        mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing) ->
+        mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing) ->
                 registerOrUnregisterDismissNotificationShadeAction();
         mStatusBar = statusBar;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 717c715..a51e3fc 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -28,6 +28,7 @@
 import android.annotation.UiContext;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.Matrix;
@@ -35,6 +36,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -76,6 +78,8 @@
         MirrorWindowControl.MirrorWindowDelegate, MagnificationGestureDetector.OnGestureListener {
 
     private static final String TAG = "WindowMagnificationController";
+    @SuppressWarnings("isloggabletaglength")
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE;
     // Delay to avoid updating state description too frequently.
     private static final int UPDATE_STATE_DESCRIPTION_DELAY_MS = 100;
     // It should be consistent with the value defined in WindowMagnificationGestureHandler.
@@ -158,14 +162,15 @@
         mRotation = display.getRotation();
 
         mWm = context.getSystemService(WindowManager.class);
-        mWindowBounds = mWm.getCurrentWindowMetrics().getBounds();
+        mWindowBounds = new Rect(mWm.getCurrentWindowMetrics().getBounds());
 
         mResources = mContext.getResources();
         mScale = mResources.getInteger(R.integer.magnification_default_scale);
         mBounceEffectDuration = mResources.getInteger(
                 com.android.internal.R.integer.config_shortAnimTime);
         updateDimensions();
-        setInitialStartBounds();
+        setMagnificationFrameWith(mWindowBounds, mWindowBounds.width() / 2,
+                mWindowBounds.height() / 2);
         computeBounceAnimationScale();
 
         mMirrorWindowControl = mirrorWindowControl;
@@ -286,18 +291,59 @@
      * @param configDiff a bit mask of the differences between the configurations
      */
     void onConfigurationChanged(int configDiff) {
+        if (DEBUG) {
+            Log.d(TAG, "onConfigurationChanged = " + Configuration.configurationDiffToString(
+                    configDiff));
+        }
+        if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
+            onRotate();
+        }
+
+        if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
+            updateAccessibilityWindowTitleIfNeeded();
+        }
+
+        boolean reCreateWindow = false;
         if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
             updateDimensions();
             computeBounceAnimationScale();
-            if (isWindowVisible()) {
-                deleteWindowMagnification();
-                enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
-            }
-        } else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
-            onRotate();
-        } else if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
-            updateAccessibilityWindowTitleIfNeeded();
+            reCreateWindow = true;
         }
+
+        if ((configDiff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
+            reCreateWindow |= handleScreenSizeChanged();
+        }
+
+        // Recreate the window again to correct the window appearance due to density or
+        // window size changed not caused by rotation.
+        if (isWindowVisible() && reCreateWindow) {
+            deleteWindowMagnification();
+            enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
+        }
+    }
+
+    /**
+     * Calculates the magnification frame if the window bounds is changed.
+     * Note that the orientation also changes the wind bounds, so it should be handled first.
+     *
+     * @return {@code true} if the magnification frame is changed with the new window bounds.
+     */
+    private boolean handleScreenSizeChanged() {
+        final Rect oldWindowBounds = new Rect(mWindowBounds);
+        final Rect currentWindowBounds = mWm.getCurrentWindowMetrics().getBounds();
+
+        if (currentWindowBounds.equals(oldWindowBounds)) {
+            if (DEBUG) {
+                Log.d(TAG, "updateMagnificationFrame -- window bounds is not changed");
+            }
+            return false;
+        }
+        mWindowBounds.set(currentWindowBounds);
+        final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
+        final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
+        setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY);
+        calculateMagnificationFrameBoundary();
+        return true;
     }
 
     private void updateSystemUIStateIfNeeded() {
@@ -311,30 +357,42 @@
         mWm.updateViewLayout(mMirrorView, params);
     }
 
-    /** Handles MirrorWindow position when the device rotation changed. */
+    /**
+     * Keep MirrorWindow position on the screen unchanged when device rotates 90° clockwise or
+     * anti-clockwise.
+     */
     private void onRotate() {
         final Display display = mContext.getDisplay();
         final int oldRotation = mRotation;
-        mWindowBounds = mWm.getCurrentWindowMetrics().getBounds();
-
-        setMagnificationFrameBoundary();
         mRotation = display.getRotation();
+        final int rotationDegree = getDegreeFromRotation(mRotation, oldRotation);
+        if (rotationDegree == 0 || rotationDegree == 180) {
+            Log.w(TAG, "onRotate -- rotate with the device. skip it");
+            return;
+        }
+        final Rect currentWindowBounds = new Rect(mWm.getCurrentWindowMetrics().getBounds());
+        if (currentWindowBounds.width() != mWindowBounds.height()
+                || currentWindowBounds.height() != mWindowBounds.width()) {
+            Log.w(TAG, "onRotate -- unexpected window height/width");
+            return;
+        }
+
+        mWindowBounds.set(currentWindowBounds);
+
+        calculateMagnificationFrameBoundary();
 
         if (!isWindowVisible()) {
             return;
         }
         // Keep MirrorWindow position on the screen unchanged when device rotates 90°
         // clockwise or anti-clockwise.
-        final int rotationDegree = getDegreeFromRotation(mRotation, oldRotation);
+
         final Matrix matrix = new Matrix();
         matrix.setRotate(rotationDegree);
         if (rotationDegree == 90) {
             matrix.postTranslate(mWindowBounds.width(), 0);
         } else if (rotationDegree == 270) {
             matrix.postTranslate(0, mWindowBounds.height());
-        } else {
-            Log.w(TAG, "Invalid rotation change. " + rotationDegree);
-            return;
         }
         // The rect of MirrorView is going to be transformed.
         LayoutParams params =
@@ -440,12 +498,12 @@
         }
     }
 
-    private void setInitialStartBounds() {
+    private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) {
         // Sets the initial frame area for the mirror and places it in the center of the display.
-        final int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 2
+        final int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2
                 + 2 * mMirrorSurfaceMargin;
-        final int initX = mWindowBounds.width() / 2 - initSize / 2;
-        final int initY = mWindowBounds.height() / 2 - initSize / 2;
+        final int initX = centerX - initSize / 2;
+        final int initY = centerY - initSize / 2;
         mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
     }
 
@@ -553,7 +611,7 @@
         mSourceBounds.set(left, top, right, bottom);
     }
 
-    private void setMagnificationFrameBoundary() {
+    private void calculateMagnificationFrameBoundary() {
         // Calculates width and height for magnification frame could exceed out the screen.
         // TODO : re-calculating again when scale is changed.
         // The half width of magnification frame.
@@ -644,7 +702,7 @@
                 : centerY - mMagnificationFrame.exactCenterY();
         mScale = Float.isNaN(scale) ? mScale : scale;
 
-        setMagnificationFrameBoundary();
+        calculateMagnificationFrameBoundary();
         updateMagnificationFramePosition((int) offsetX, (int) offsetY);
         if (!isWindowVisible()) {
             createMirrorWindow();
@@ -764,6 +822,8 @@
         pw.println("      mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
         pw.println("      mScale:" + mScale);
         pw.println("      mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
+        pw.println("      mSourceBounds:"
+                 + (isWindowVisible() ? mSourceBounds : "empty"));
         pw.println("      mSystemGestureTop:" + mSystemGestureTop);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 567d0cb..557bca8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -120,7 +120,7 @@
     private val onSeedingComplete = Consumer<Boolean> {
         accepted ->
             if (accepted) {
-                selectedStructure = controlsController.get().getFavorites().maxBy {
+                selectedStructure = controlsController.get().getFavorites().maxByOrNull {
                     it.controls.size
                 } ?: EMPTY_STRUCTURE
                 updatePreferences(selectedStructure)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index c97a30e..83fa994 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -60,9 +60,11 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationBarA11yHelper;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBarOverlayController;
 import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.navigationbar.TaskbarDelegate;
 import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.ReduceBrightColorsController;
@@ -234,6 +236,8 @@
             UiEventLogger uiEventLogger,
             NavigationBarOverlayController navBarOverlayController,
             ConfigurationController configurationController,
+            NavigationBarA11yHelper navigationBarA11yHelper,
+            TaskbarDelegate taskbarDelegate,
             UserTracker userTracker) {
         return new NavigationBarController(context,
                 windowManager,
@@ -261,6 +265,8 @@
                 uiEventLogger,
                 navBarOverlayController,
                 configurationController,
+                navigationBarA11yHelper,
+                taskbarDelegate,
                 userTracker);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index bc4ced4..98fb3c9 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -199,7 +199,6 @@
                 iWindowManager,
                 backgroundExecutor,
                 uiEventLogger,
-                null,
                 ringerModeTracker,
                 sysUiState,
                 handler,
@@ -338,8 +337,7 @@
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
                     adapter, overflowAdapter, sysuiColorExtractor, statusBarService,
                     notificationShadeWindowController, sysuiState, onRotateCallback,
-                    keyguardShowing, powerAdapter, uiEventLogger, null,
-                    statusBar);
+                    keyguardShowing, powerAdapter, uiEventLogger, statusBar);
             mWalletFactory = walletFactory;
 
             // Update window attributes
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 5acb303..6a458a3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -190,7 +190,6 @@
     private final MetricsLogger mMetricsLogger;
     private final UiEventLogger mUiEventLogger;
     private final SysUiState mSysUiState;
-    private final GlobalActionsInfoProvider mInfoProvider;
 
     // Used for RingerModeTracker
     private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
@@ -333,7 +332,6 @@
             IWindowManager iWindowManager,
             @Background Executor backgroundExecutor,
             UiEventLogger uiEventLogger,
-            GlobalActionsInfoProvider infoProvider,
             RingerModeTracker ringerModeTracker,
             SysUiState sysUiState,
             @Main Handler handler,
@@ -358,7 +356,6 @@
         mTelecomManager = telecomManager;
         mMetricsLogger = metricsLogger;
         mUiEventLogger = uiEventLogger;
-        mInfoProvider = infoProvider;
         mSysuiColorExtractor = colorExtractor;
         mStatusBarService = statusBarService;
         mNotificationShadeWindowController = notificationShadeWindowController;
@@ -653,7 +650,7 @@
                 mAdapter, mOverflowAdapter, mSysuiColorExtractor,
                 mStatusBarService, mNotificationShadeWindowController,
                 mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
-                mInfoProvider, mStatusBar);
+                mStatusBar);
 
         dialog.setOnDismissListener(this);
         dialog.setOnShowListener(this);
@@ -2124,7 +2121,6 @@
         private Dialog mPowerOptionsDialog;
         protected final Runnable mOnRotateCallback;
         private UiEventLogger mUiEventLogger;
-        private GlobalActionsInfoProvider mInfoProvider;
         private GestureDetector mGestureDetector;
         private StatusBar mStatusBar;
 
@@ -2178,7 +2174,7 @@
                 NotificationShadeWindowController notificationShadeWindowController,
                 SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
                 MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
-                @Nullable GlobalActionsInfoProvider infoProvider, StatusBar statusBar) {
+                StatusBar statusBar) {
             super(context, themeRes);
             mContext = context;
             mAdapter = adapter;
@@ -2191,7 +2187,6 @@
             mOnRotateCallback = onRotateCallback;
             mKeyguardShowing = keyguardShowing;
             mUiEventLogger = uiEventLogger;
-            mInfoProvider = infoProvider;
             mStatusBar = statusBar;
 
             mGestureDetector = new GestureDetector(mContext, mGestureListener);
@@ -2309,10 +2304,6 @@
                 mBackgroundDrawable = new ScrimDrawable();
                 mScrimAlpha = 1.0f;
             }
-
-            if (mInfoProvider != null && mInfoProvider.shouldShowMessage()) {
-                mInfoProvider.addPanel(mContext, mContainer, mAdapter.getCount(), () -> dismiss());
-            }
         }
 
         protected void fixNavBarClipping() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsInfoProvider.kt b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsInfoProvider.kt
deleted file mode 100644
index 17b532a..0000000
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsInfoProvider.kt
+++ /dev/null
@@ -1,122 +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.globalactions
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.content.res.Configuration
-import android.net.Uri
-import android.service.quickaccesswallet.QuickAccessWalletClient
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
-import com.android.systemui.R
-import com.android.systemui.controls.controller.ControlsController
-import com.android.systemui.plugins.ActivityStarter
-import javax.inject.Inject
-
-private const val TAG = "GlobalActionsInfo"
-
-/** Maximum number of times to show change info message  */
-private const val MAX_VIEW_COUNT = 3
-
-/** Maximum number of buttons allowed in landscape before this panel does not fit */
-private const val MAX_BUTTONS_LANDSCAPE = 4
-
-private const val PREFERENCE = "global_actions_info_prefs"
-private const val KEY_VIEW_COUNT = "view_count"
-
-class GlobalActionsInfoProvider @Inject constructor(
-    private val context: Context,
-    private val walletClient: QuickAccessWalletClient,
-    private val controlsController: ControlsController,
-    private val activityStarter: ActivityStarter
-) {
-
-    private var pendingIntent: PendingIntent
-
-    init {
-        val url = context.resources.getString(R.string.global_actions_change_url)
-        val intent = Intent(Intent.ACTION_VIEW).apply {
-            setData(Uri.parse(url))
-            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        }
-        pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
-    }
-
-    fun addPanel(context: Context, parent: ViewGroup, nActions: Int, dismissParent: Runnable) {
-        // This panel does not fit on landscape with two rows of buttons showing,
-        // so skip adding the panel (and incrementing view counT) in that case
-        val isLandscape =
-                context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
-        if (isLandscape && nActions > MAX_BUTTONS_LANDSCAPE) {
-            return
-        }
-
-        val view = LayoutInflater.from(context).inflate(R.layout.global_actions_change_panel,
-                parent, false)
-
-        val walletTitle = walletClient.serviceLabel ?: context.getString(R.string.wallet_title)
-        val message = view.findViewById<TextView>(R.id.global_actions_change_message)
-        message?.setText(context.getString(R.string.global_actions_change_description, walletTitle))
-
-        val button = view.findViewById<ImageView>(R.id.global_actions_change_button)
-        button.setOnClickListener { _ ->
-            dismissParent.run()
-            activityStarter.postStartActivityDismissingKeyguard(pendingIntent)
-        }
-        parent.addView(view, 0) // Add to top
-        incrementViewCount()
-    }
-
-    fun shouldShowMessage(): Boolean {
-        // This is only relevant for some devices
-        val isEligible = context.resources.getBoolean(
-                R.bool.global_actions_show_change_info)
-        if (!isEligible) {
-            return false
-        }
-
-        val sharedPrefs = context.getSharedPreferences(PREFERENCE, Context.MODE_PRIVATE)
-
-        // Only show to users who previously had these items set up
-        val viewCount = if (sharedPrefs.contains(KEY_VIEW_COUNT) || hadContent()) {
-            sharedPrefs.getInt(KEY_VIEW_COUNT, 0)
-        } else {
-            -1
-        }
-
-        // Limit number of times this is displayed
-        return viewCount > -1 && viewCount < MAX_VIEW_COUNT
-    }
-
-    private fun hadContent(): Boolean {
-        // Check whether user would have seen content in the power menu that has now moved
-        val hadControls = controlsController.getFavorites().size > 0
-        val hadCards = walletClient.isWalletFeatureAvailable
-        Log.d(TAG, "Previously had controls $hadControls, cards $hadCards")
-        return hadControls || hadCards
-    }
-
-    private fun incrementViewCount() {
-        val sharedPrefs = context.getSharedPreferences(PREFERENCE, Context.MODE_PRIVATE)
-        val count = sharedPrefs.getInt(KEY_VIEW_COUNT, 0)
-        sharedPrefs.edit().putInt(KEY_VIEW_COUNT, count + 1).apply()
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 26f38dd..7f42530 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -23,10 +23,12 @@
 import static android.app.StatusBarManager.WindowType;
 import static android.app.StatusBarManager.WindowVisibleState;
 import static android.app.StatusBarManager.windowStateToString;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.containsType;
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
@@ -44,6 +46,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -54,9 +57,7 @@
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
 import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
 
-import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.IdRes;
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
@@ -68,6 +69,7 @@
 import android.content.IntentFilter;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -101,7 +103,6 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 import android.view.inputmethod.InputMethodManager;
 
 import androidx.annotation.VisibleForTesting;
@@ -130,6 +131,7 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.AutoHideUiElement;
@@ -151,7 +153,6 @@
 import com.android.wm.shell.pip.Pip;
 
 import java.io.PrintWriter;
-import java.util.List;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.function.Consumer;
@@ -162,8 +163,7 @@
  * Contains logic for a navigation bar view.
  */
 public class NavigationBar implements View.OnAttachStateChangeListener,
-        Callbacks, NavigationModeController.ModeChangedListener,
-        AccessibilityButtonModeObserver.ModeChangedListener {
+        Callbacks, NavigationModeController.ModeChangedListener {
 
     public static final String TAG = "NavigationBar";
     private static final boolean DEBUG = false;
@@ -180,7 +180,6 @@
     private final Context mContext;
     private final WindowManager mWindowManager;
     private final AccessibilityManager mAccessibilityManager;
-    private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final StatusBarStateController mStatusBarStateController;
     private final MetricsLogger mMetricsLogger;
@@ -201,11 +200,13 @@
     private final Handler mHandler;
     private final NavigationBarOverlayController mNavbarOverlayController;
     private final UiEventLogger mUiEventLogger;
+    private final NavigationBarA11yHelper mNavigationBarA11yHelper;
     private final UserTracker mUserTracker;
     private final NotificationShadeDepthController mNotificationShadeDepthController;
 
     private Bundle mSavedState;
     private NavigationBarView mNavigationBarView;
+    private NavigationBarFrame mFrame;
 
     private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
 
@@ -483,11 +484,11 @@
             @Main Handler mainHandler,
             NavigationBarOverlayController navbarOverlayController,
             UiEventLogger uiEventLogger,
+            NavigationBarA11yHelper navigationBarA11yHelper,
             UserTracker userTracker) {
         mContext = context;
         mWindowManager = windowManager;
         mAccessibilityManager = accessibilityManager;
-        mAccessibilityManagerWrapper = accessibilityManagerWrapper;
         mDeviceProvisionedController = deviceProvisionedController;
         mStatusBarStateController = statusBarStateController;
         mMetricsLogger = metricsLogger;
@@ -508,11 +509,11 @@
         mHandler = mainHandler;
         mNavbarOverlayController = navbarOverlayController;
         mUiEventLogger = uiEventLogger;
+        mNavigationBarA11yHelper = navigationBarA11yHelper;
         mUserTracker = userTracker;
         mNotificationShadeDepthController = notificationShadeDepthController;
 
         mNavBarMode = mNavigationModeController.addListener(this);
-        mAccessibilityButtonModeObserver.addListener(this);
     }
 
     public NavigationBarView getView() {
@@ -520,34 +521,17 @@
     }
 
     public View createView(Bundle savedState) {
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
-                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
-                PixelFormat.TRANSLUCENT);
-        lp.token = new Binder();
-        lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
-        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        lp.windowAnimations = 0;
-        lp.setTitle("NavigationBar" + mContext.getDisplayId());
-        lp.setFitInsetsTypes(0 /* types */);
-        lp.setTrustedOverlay();
-
-        NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
+        mFrame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
                 R.layout.navigation_bar_window, null);
-        View barView = LayoutInflater.from(frame.getContext()).inflate(
-                R.layout.navigation_bar, frame);
+        View barView = LayoutInflater.from(mFrame.getContext()).inflate(
+                R.layout.navigation_bar, mFrame);
         barView.addOnAttachStateChangeListener(this);
         mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
 
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
-        mContext.getSystemService(WindowManager.class).addView(frame, lp);
+        mContext.getSystemService(WindowManager.class).addView(mFrame,
+                getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
+                        .getRotation()));
         mDisplayId = mContext.getDisplayId();
         mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
 
@@ -605,9 +589,8 @@
         mContext.getSystemService(WindowManager.class).removeViewImmediate(
                 mNavigationBarView.getRootView());
         mNavigationModeController.removeListener(this);
-        mAccessibilityButtonModeObserver.removeListener(this);
 
-        mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
+        mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
         mContentResolver.unregisterContentObserver(mAssistContentObserver);
         mDeviceProvisionedController.removeCallback(mUserSetupListener);
         mNotificationShadeDepthController.removeListener(mDepthListener);
@@ -629,7 +612,7 @@
         mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
         mNavigationBarView.setBehavior(mBehavior);
 
-        mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
+        mNavigationBarA11yHelper.registerA11yEventListener(mAccessibilityListener);
 
         mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
         mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
@@ -704,6 +687,7 @@
         mHandler.removeCallbacks(mAutoDim);
         mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
         mHandler.removeCallbacks(mEnableLayoutTransitions);
+        mFrame = null;
         mNavigationBarView = null;
         mOrientationHandle = null;
     }
@@ -722,6 +706,7 @@
      * Called when a non-reloading configuration change happens and we need to update.
      */
     public void onConfigurationChanged(Configuration newConfig) {
+        final int rotation = newConfig.windowConfiguration.getRotation();
         final Locale locale = mContext.getResources().getConfiguration().locale;
         final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
         if (!locale.equals(mLocale) || ld != mLayoutDirection) {
@@ -735,9 +720,8 @@
             refreshLayout(ld);
         }
 
-        repositionNavigationBar();
+        repositionNavigationBar(rotation);
         if (canShowSecondaryHandle()) {
-            int rotation = newConfig.windowConfiguration.getRotation();
             if (rotation != mCurrentRotation) {
                 mCurrentRotation = rotation;
                 orientSecondaryHomeHandle();
@@ -889,26 +873,8 @@
             return;
         }
         boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
-        int hints = mNavigationIconHints;
-        switch (backDisposition) {
-            case InputMethodService.BACK_DISPOSITION_DEFAULT:
-            case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
-            case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
-                if (imeShown) {
-                    hints |= NAVIGATION_HINT_BACK_ALT;
-                } else {
-                    hints &= ~NAVIGATION_HINT_BACK_ALT;
-                }
-                break;
-            case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
-                hints &= ~NAVIGATION_HINT_BACK_ALT;
-                break;
-        }
-        if (showImeSwitcher) {
-            hints |= NAVIGATION_HINT_IME_SHOWN;
-        } else {
-            hints &= ~NAVIGATION_HINT_IME_SHOWN;
-        }
+        int hints = Utilities.calculateBackDispositionHints(mNavigationIconHints, backDisposition,
+                imeShown, showImeSwitcher);
         if (hints == mNavigationIconHints) return;
 
         mNavigationIconHints = hints;
@@ -1120,13 +1086,12 @@
                 || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
-    private void repositionNavigationBar() {
-        if (!mNavigationBarView.isAttachedToWindow()) return;
+    private void repositionNavigationBar(int rotation) {
+        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
 
         prepareNavigationBarView();
 
-        mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
-                ((View) mNavigationBarView.getParent()).getLayoutParams());
+        mWindowManager.updateViewLayout(mFrame, getBarLayoutParams(rotation));
     }
 
     private void updateScreenPinningGestures() {
@@ -1168,7 +1133,7 @@
         ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
-        updateAccessibilityServicesState(mAccessibilityManager);
+        updateAccessibilityServicesState();
 
         ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
         imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
@@ -1389,9 +1354,8 @@
         return true;
     }
 
-    void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
-        boolean[] feedbackEnabled = new boolean[1];
-        int a11yFlags = getA11yButtonState(feedbackEnabled);
+    void updateAccessibilityServicesState() {
+        int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
 
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
@@ -1410,7 +1374,7 @@
 
     public void updateSystemUiStateFlags(int a11yFlags) {
         if (a11yFlags < 0) {
-            a11yFlags = getA11yButtonState(null);
+            a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
         }
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
@@ -1420,6 +1384,8 @@
                 .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isNavBarWindowVisible())
                 .setFlag(SYSUI_STATE_IME_SHOWING,
                         (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
+                .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING,
+                        (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0)
                 .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
                         allowSystemGestureIgnoringBarVisibility())
                 .commitUpdate(mDisplayId);
@@ -1435,45 +1401,6 @@
         }
     }
 
-    /**
-     * Returns the system UI flags corresponding the the current accessibility button state
-     *
-     * @param outFeedbackEnabled if non-null, sets it to true if accessibility feedback is enabled.
-     */
-    public int getA11yButtonState(@Nullable boolean[] outFeedbackEnabled) {
-        boolean feedbackEnabled = false;
-        // AccessibilityManagerService resolves services for the current user since the local
-        // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
-        final List<AccessibilityServiceInfo> services =
-                mAccessibilityManager.getEnabledAccessibilityServiceList(
-                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
-        final List<String> a11yButtonTargets =
-                mAccessibilityManager.getAccessibilityShortcutTargets(
-                        AccessibilityManager.ACCESSIBILITY_BUTTON);
-        final int requestingServices = a11yButtonTargets.size();
-        for (int i = services.size() - 1; i >= 0; --i) {
-            AccessibilityServiceInfo info = services.get(i);
-            if (info.feedbackType != 0 && info.feedbackType !=
-                    AccessibilityServiceInfo.FEEDBACK_GENERIC) {
-                feedbackEnabled = true;
-            }
-        }
-
-        if (outFeedbackEnabled != null) {
-            outFeedbackEnabled[0] = feedbackEnabled;
-        }
-
-        // If accessibility button is floating menu mode, click and long click state should be
-        // disabled.
-        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
-                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
-            return 0;
-        }
-
-        return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
-                | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
-    }
-
     private void updateAssistantEntrypoints() {
         mAssistantAvailable = mAssistManagerLazy.get()
                 .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
@@ -1575,11 +1502,6 @@
         }
     }
 
-    @Override
-    public void onAccessibilityButtonModeChanged(int mode) {
-        updateAccessibilityServicesState(mAccessibilityManager);
-    }
-
     public void disableAnimationsDuringHide(long delay) {
         mNavigationBarView.setLayoutTransitionsEnabled(false);
         mHandler.postDelayed(mEnableLayoutTransitions,
@@ -1604,22 +1526,110 @@
         mNavigationBarView.getBarTransitions().finishAnimations();
     }
 
-    private final AccessibilityServicesStateChangeListener mAccessibilityListener =
+    private final NavigationBarA11yHelper.NavA11yEventListener mAccessibilityListener =
             this::updateAccessibilityServicesState;
 
+    private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
+        WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
+        lp.paramsForRotation = new WindowManager.LayoutParams[4];
+        for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+            lp.paramsForRotation[rot] = getBarLayoutParamsForRotation(rot);
+        }
+        return lp;
+    }
+
+    private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
+        int width = WindowManager.LayoutParams.MATCH_PARENT;
+        int height = WindowManager.LayoutParams.MATCH_PARENT;
+        int insetsHeight = -1;
+        int gravity = Gravity.BOTTOM;
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            boolean navBarCanMove = true;
+            if (mWindowManager != null && mWindowManager.getCurrentWindowMetrics() != null) {
+                Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds();
+                navBarCanMove = displaySize.width() != displaySize.height()
+                        && mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_navBarCanMove);
+            }
+            if (!navBarCanMove) {
+                height = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.navigation_bar_frame_height);
+                insetsHeight = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.navigation_bar_height);
+            } else {
+                switch (rotation) {
+                    case ROTATION_UNDEFINED:
+                    case Surface.ROTATION_0:
+                    case Surface.ROTATION_180:
+                        height = mContext.getResources().getDimensionPixelSize(
+                                com.android.internal.R.dimen.navigation_bar_frame_height);
+                        insetsHeight = mContext.getResources().getDimensionPixelSize(
+                                com.android.internal.R.dimen.navigation_bar_height);
+                        break;
+                    case Surface.ROTATION_90:
+                        gravity = Gravity.RIGHT;
+                        width = mContext.getResources().getDimensionPixelSize(
+                                com.android.internal.R.dimen.navigation_bar_width);
+                        break;
+                    case Surface.ROTATION_270:
+                        gravity = Gravity.LEFT;
+                        width = mContext.getResources().getDimensionPixelSize(
+                                com.android.internal.R.dimen.navigation_bar_width);
+                        break;
+                }
+            }
+        }
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                width,
+                height,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
+                PixelFormat.TRANSLUCENT);
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            lp.gravity = gravity;
+            if (insetsHeight != -1) {
+                lp.providedInternalInsets = Insets.of(0, height - insetsHeight, 0, 0);
+            } else {
+                lp.providedInternalInsets = Insets.NONE;
+            }
+        }
+        lp.token = new Binder();
+        lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        lp.windowAnimations = 0;
+        lp.setTitle("NavigationBar" + mContext.getDisplayId());
+        lp.setFitInsetsTypes(0 /* types */);
+        lp.setTrustedOverlay();
+        return lp;
+    }
+
     private boolean canShowSecondaryHandle() {
         return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null;
     }
 
     private final Consumer<Integer> mRotationWatcher = rotation -> {
-        if (mNavigationBarView.needsReorient(rotation)) {
-            repositionNavigationBar();
+        if (mNavigationBarView != null
+                && mNavigationBarView.needsReorient(rotation)) {
+            repositionNavigationBar(rotation);
         }
     };
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            // This receiver is unregistered when the view is detached, but on devices with multiple
+            // displays, it can sometimes still receive an ACTION_SCREEN_ON/ACTION_SCREEN_OFF on
+            // display switch, after it was detached, so this null check ensures no crash in that
+            // scenario.
+            if (mNavigationBarView == null) {
+                return;
+            }
             String action = intent.getAction();
             if (Intent.ACTION_SCREEN_OFF.equals(action)
                     || Intent.ACTION_SCREEN_ON.equals(action)) {
@@ -1628,7 +1638,7 @@
             }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 // The accessibility settings may be different for the new user
-                updateAccessibilityServicesState(mAccessibilityManager);
+                updateAccessibilityServicesState();
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarA11yHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarA11yHelper.java
new file mode 100644
index 0000000..13e6d8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarA11yHelper.java
@@ -0,0 +1,90 @@
+package com.android.systemui.navigationbar;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/**
+ * Extracts shared elements of a11y necessary between navbar and taskbar delegate
+ */
+@SysUISingleton
+public final class NavigationBarA11yHelper implements
+        AccessibilityButtonModeObserver.ModeChangedListener {
+    private final AccessibilityManager mAccessibilityManager;
+    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+    private final List<NavA11yEventListener> mA11yEventListeners = new ArrayList<>();
+
+    @Inject
+    public NavigationBarA11yHelper(AccessibilityManager accessibilityManager,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver) {
+        mAccessibilityManager = accessibilityManager;
+        accessibilityManagerWrapper.addCallback(
+                accessibilityManager1 -> NavigationBarA11yHelper.this.dispatchEventUpdate());
+        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
+
+        mAccessibilityButtonModeObserver.addListener(this);
+    }
+
+    public void registerA11yEventListener(NavA11yEventListener listener) {
+        mA11yEventListeners.add(listener);
+    }
+
+    public void removeA11yEventListener(NavA11yEventListener listener) {
+        mA11yEventListeners.remove(listener);
+    }
+
+    private void dispatchEventUpdate() {
+        for (NavA11yEventListener listener : mA11yEventListeners) {
+            listener.updateAccessibilityServicesState();
+        }
+    }
+
+    @Override
+    public void onAccessibilityButtonModeChanged(int mode) {
+        dispatchEventUpdate();
+    }
+
+    /**
+     * See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
+     * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
+     *
+     * @return the a11y button clickable and long_clickable states, or 0 if there is no
+     *         a11y button in the navbar
+     */
+    public int getA11yButtonState() {
+        // AccessibilityManagerService resolves services for the current user since the local
+        // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
+        final List<String> a11yButtonTargets =
+                mAccessibilityManager.getAccessibilityShortcutTargets(
+                        AccessibilityManager.ACCESSIBILITY_BUTTON);
+        final int requestingServices = a11yButtonTargets.size();
+
+        // If accessibility button is floating menu mode, click and long click state should be
+        // disabled.
+        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
+                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+            return 0;
+        }
+
+        return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
+                | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
+    }
+
+    public interface NavA11yEventListener {
+        void updateAccessibilityServicesState();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index b9e9240..aa5964b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -27,7 +27,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.os.SystemProperties;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseArray;
@@ -113,6 +112,7 @@
     private final SystemActions mSystemActions;
     private final UiEventLogger mUiEventLogger;
     private final Handler mHandler;
+    private final NavigationBarA11yHelper mNavigationBarA11yHelper;
     private final DisplayManager mDisplayManager;
     private final NavigationBarOverlayController mNavBarOverlayController;
     private final TaskbarDelegate mTaskbarDelegate;
@@ -157,6 +157,8 @@
             UiEventLogger uiEventLogger,
             NavigationBarOverlayController navBarOverlayController,
             ConfigurationController configurationController,
+            NavigationBarA11yHelper navigationBarA11yHelper,
+            TaskbarDelegate taskbarDelegate,
             UserTracker userTracker) {
         mContext = context;
         mWindowManager = windowManager;
@@ -182,6 +184,7 @@
         mSystemActions = systemActions;
         mUiEventLogger = uiEventLogger;
         mHandler = mainHandler;
+        mNavigationBarA11yHelper = navigationBarA11yHelper;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
         commandQueue.addCallback(this);
         configurationController.addCallback(this);
@@ -189,7 +192,9 @@
         mNavBarOverlayController = navBarOverlayController;
         mNavMode = mNavigationModeController.addListener(this);
         mNavigationModeController.addListener(this);
-        mTaskbarDelegate = new TaskbarDelegate(mOverviewProxyService);
+        mTaskbarDelegate = taskbarDelegate;
+        mTaskbarDelegate.setOverviewProxyService(overviewProxyService,
+                navigationBarA11yHelper, mSysUiFlagsContainer);
         mIsTablet = isTablet(mContext.getResources().getConfiguration());
         mUserTracker = userTracker;
     }
@@ -237,25 +242,28 @@
         });
     }
 
-    /**
-     * @return {@code true} if navbar was added/removed, false otherwise
-     */
-    public boolean updateNavbarForTaskbar() {
-        if (!isThreeButtonTaskbarFlagEnabled()) {
-            return false;
+    /** @see #initializeTaskbarIfNecessary() */
+    private boolean updateNavbarForTaskbar() {
+        boolean taskbarShown = initializeTaskbarIfNecessary();
+        if (!taskbarShown && mNavigationBars.get(mContext.getDisplayId()) == null) {
+            createNavigationBar(mContext.getDisplay(), null, null);
         }
+        return taskbarShown;
+    }
 
-        if (mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON) {
+    /** @return {@code true} if taskbar is enabled, false otherwise */
+    private boolean initializeTaskbarIfNecessary() {
+        boolean isShowingTaskbar = mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON;
+        if (isShowingTaskbar) {
             // Remove navigation bar when taskbar is showing, currently only for 3 button mode
             removeNavigationBar(mContext.getDisplayId());
             mCommandQueue.addCallback(mTaskbarDelegate);
-        } else if (mNavigationBars.get(mContext.getDisplayId()) == null) {
-            // Add navigation bar after taskbar goes away
-            createNavigationBar(mContext.getDisplay(), null, null);
+            mTaskbarDelegate.init(mContext.getDisplayId());
+        } else {
             mCommandQueue.removeCallback(mTaskbarDelegate);
+            mTaskbarDelegate.destroy();
         }
-
-        return true;
+        return isShowingTaskbar;
     }
 
     @Override
@@ -302,7 +310,7 @@
      */
     public void createNavigationBars(final boolean includeDefaultDisplay,
             RegisterStatusBarResult result) {
-        if (updateNavbarForTaskbar()) {
+        if (initializeTaskbarIfNecessary()) {
             return;
         }
 
@@ -326,7 +334,7 @@
             return;
         }
 
-        if (isThreeButtonTaskbarEnabled()) {
+        if (mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON) {
             return;
         }
 
@@ -371,6 +379,7 @@
                 mHandler,
                 mNavBarOverlayController,
                 mUiEventLogger,
+                mNavigationBarA11yHelper,
                 mUserTracker);
         mNavigationBars.put(displayId, navBar);
 
@@ -462,15 +471,6 @@
         return mNavigationBars.get(DEFAULT_DISPLAY);
     }
 
-    private boolean isThreeButtonTaskbarEnabled() {
-        return mIsTablet && mNavMode == NAV_BAR_MODE_3BUTTON &&
-                isThreeButtonTaskbarFlagEnabled();
-    }
-
-    private boolean isThreeButtonTaskbarFlagEnabled() {
-        return SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
-    }
-
     private boolean isTablet(Configuration newConfig) {
         float density = Resources.getSystem().getDisplayMetrics().density;
         int size = Math.min((int) (density * newConfig.screenWidthDp),
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index 649ac87..a5b7911 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -47,6 +47,8 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.utilities.ViewRippler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -311,7 +313,7 @@
 
         // Prepare to show the navbar icon by updating the icon style to change anim params
         mLastRotationSuggestion = rotation; // Remember rotation for click
-        final boolean rotationCCW = isRotationAnimationCCW(windowRotation, rotation);
+        final boolean rotationCCW = Utilities.isRotationAnimationCCW(windowRotation, rotation);
         if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) {
             mIconResId = rotationCCW
                     ? R.drawable.ic_sysbar_rotate_button_ccw_start_90
@@ -431,23 +433,6 @@
         return rotation == NATURAL_ROTATION;
     }
 
-    private boolean isRotationAnimationCCW(int from, int to) {
-        // All 180deg WM rotation animations are CCW, match that
-        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false;
-        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW
-        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true;
-        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true;
-        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false;
-        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW
-        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW
-        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true;
-        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false;
-        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false;
-        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW
-        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true;
-        return false; // Default
-    }
-
     private void rescheduleRotationTimeout(final boolean reasonHover) {
         // May be called due to a new rotation proposal or a change in hover state
         if (reasonHover) {
@@ -520,38 +505,6 @@
         }
     }
 
-    private class ViewRippler {
-        private static final int RIPPLE_OFFSET_MS = 50;
-        private static final int RIPPLE_INTERVAL_MS = 2000;
-        private View mRoot;
-
-        public void start(View root) {
-            stop(); // Stop any pending ripple animations
-
-            mRoot = root;
-
-            // Schedule pending ripples, offset the 1st to avoid problems with visibility change
-            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
-            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
-            mRoot.postOnAnimationDelayed(mRipple, 2 * RIPPLE_INTERVAL_MS);
-            mRoot.postOnAnimationDelayed(mRipple, 3 * RIPPLE_INTERVAL_MS);
-            mRoot.postOnAnimationDelayed(mRipple, 4 * RIPPLE_INTERVAL_MS);
-        }
-
-        public void stop() {
-            if (mRoot != null) mRoot.removeCallbacks(mRipple);
-        }
-
-        private final Runnable mRipple = new Runnable() {
-            @Override
-            public void run() { // Cause the ripple to fire via false presses
-                if (!mRoot.isAttachedToWindow()) return;
-                mRoot.setPressed(true /* pressed */);
-                mRoot.setPressed(false /* pressed */);
-            }
-        };
-    }
-
     enum RotationButtonEvent implements UiEventLogger.UiEventEnum {
         @UiEvent(doc = "The rotation button was shown")
         ROTATION_SUGGESTION_SHOWN(206),
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 03147d8..40afed3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -16,23 +16,99 @@
 
 package com.android.systemui.navigationbar;
 
+import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+
+import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 
+import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.statusbar.CommandQueue;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
 public class TaskbarDelegate implements CommandQueue.Callbacks {
 
-    private final OverviewProxyService mOverviewProxyService;
+    private OverviewProxyService mOverviewProxyService;
+    private NavigationBarA11yHelper mNavigationBarA11yHelper;
+    private SysUiState mSysUiState;
+    private int mDisplayId;
+    private int mNavigationIconHints;
+    private final NavigationBarA11yHelper.NavA11yEventListener mNavA11yEventListener =
+            this::updateSysuiFlags;
+    @Inject
+    public TaskbarDelegate() { /* no-op */ }
 
-    public TaskbarDelegate(OverviewProxyService overviewProxyService) {
+    public void setOverviewProxyService(OverviewProxyService overviewProxyService,
+            NavigationBarA11yHelper navigationBarA11yHelper,
+            SysUiState sysUiState) {
+        // TODO: adding this in the ctor results in a dagger dependency cycle :(
         mOverviewProxyService = overviewProxyService;
+        mNavigationBarA11yHelper = navigationBarA11yHelper;
+        mSysUiState = sysUiState;
+    }
+
+    public void destroy() {
+        mNavigationBarA11yHelper.removeA11yEventListener(mNavA11yEventListener);
+    }
+
+    public void init(int displayId) {
+        mDisplayId = displayId;
+        mNavigationBarA11yHelper.registerA11yEventListener(mNavA11yEventListener);
+        // Set initial state for any listeners
+        updateSysuiFlags();
+    }
+
+    private void updateSysuiFlags() {
+        int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
+        boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+        boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+
+        mSysUiState.setFlag(SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable)
+                .setFlag(SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable)
+                .setFlag(SYSUI_STATE_IME_SHOWING,
+                        (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
+                .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING,
+                        (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0)
+                .commitUpdate(mDisplayId);
     }
 
     @Override
     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
-        mOverviewProxyService.notifyImeWindowStatus(displayId, token, vis, backDisposition,
-                showImeSwitcher);
+        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
+        int hints = Utilities.calculateBackDispositionHints(mNavigationIconHints, backDisposition,
+                imeShown, showImeSwitcher);
+        if (hints != mNavigationIconHints) {
+            mNavigationIconHints = hints;
+            updateSysuiFlags();
+        }
+    }
+
+    @Override
+    public void onRotationProposal(int rotation, boolean isValid) {
+        mOverviewProxyService.onRotationProposal(rotation, isValid);
+    }
+
+    @Override
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        mOverviewProxyService.disable(displayId, state1, state2, animate);
+    }
+
+    @Override
+    public void onSystemBarAttributesChanged(int displayId, int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
+            boolean isFullscreen) {
+        mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
index 1d2e747..eec69f98 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
@@ -28,7 +28,7 @@
         appsAndTypes = itemsList.groupBy({ it.application }, { it.privacyType })
                 .toList()
                 .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
-                        { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest)
+                        { it.second.minOrNull() })) // Sort by "smallest" AppOpp (Location is largest)
         types = itemsList.map { it.privacyType }.distinct().sorted()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index cb0c411..5325943 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -34,6 +34,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -736,12 +737,13 @@
     }
 
     private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
-            boolean bouncerShowing) {
+            boolean bouncerShowing, boolean isDozing) {
         mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
                         keyguardShowing && !keyguardOccluded)
                 .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
                         keyguardShowing && keyguardOccluded)
                 .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing)
+                .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing)
                 .commitUpdate(mContext.getDisplayId());
     }
 
@@ -967,19 +969,40 @@
         }
     }
 
-    public void notifyImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
         try {
             if (mOverviewProxy != null) {
-                mOverviewProxy.onImeWindowStatusChanged(displayId, token, vis, backDisposition,
-                        showImeSwitcher);
+                mOverviewProxy.disable(displayId, state1, state2, animate);
             } else {
-                Log.e(TAG_OPS, "Failed to get overview proxy for setting IME status.");
+                Log.e(TAG_OPS, "Failed to get overview proxy for disable flags.");
             }
         } catch (RemoteException e) {
-            Log.e(TAG_OPS, "Failed to call notifyImeWindowStatus()", e);
+            Log.e(TAG_OPS, "Failed to call disable()", e);
         }
+    }
 
+    public void onRotationProposal(int rotation, boolean isValid) {
+        try {
+            if (mOverviewProxy != null) {
+                mOverviewProxy.onRotationProposal(rotation, isValid);
+            } else {
+                Log.e(TAG_OPS, "Failed to get overview proxy for proposing rotation.");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG_OPS, "Failed to call onRotationProposal()", e);
+        }
+    }
+
+    public void onSystemBarAttributesChanged(int displayId, int behavior) {
+        try {
+            if (mOverviewProxy != null) {
+                mOverviewProxy.onSystemBarAttributesChanged(displayId, behavior);
+            } else {
+                Log.e(TAG_OPS, "Failed to get overview proxy for system bar attr change.");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG_OPS, "Failed to call onSystemBarAttributesChanged()", e);
+        }
     }
 
     private void updateEnabledState() {
@@ -1030,7 +1053,5 @@
         default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
         default void onAssistantGestureCompletion(float velocity) {}
         default void startAssistant(Bundle bundle) {}
-        default void onImeWindowStatusChanged(int displayId, IBinder token, int vis,
-                int backDisposition, boolean showImeSwitcher) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index e7e9404..c681a44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -285,6 +285,7 @@
         internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
         mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
 
+        mCurrentUserId = ActivityManager.getCurrentUser(); // in case we reg'd receiver too late
         updateCurrentProfilesCache();
 
         mSettingsObserver.onChange(false);  // set up
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 96b0e78..9574b54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -127,11 +127,8 @@
     public int targetSdk;
     private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
     public CharSequence remoteInputText;
-    // Mimetype and Uri used to display the image in the notification *after* it has been sent.
     public String remoteInputMimeType;
     public Uri remoteInputUri;
-    // ContentInfo used to keep the attachment permission alive until RemoteInput is sent or
-    // cancelled.
     public ContentInfo remoteInputAttachment;
     private Notification.BubbleMetadata mBubbleMetadata;
     private ShortcutInfo mShortcutInfo;
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 ba2f555..35914c0 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
@@ -5641,6 +5641,10 @@
         mSwipeHelper.resetExposedMenuView(animate, force);
     }
 
+    boolean isUsingSplitNotificationShade() {
+        return mShouldUseSplitNotificationShade;
+    }
+
     static boolean matchesSelection(
             ExpandableNotificationRow row,
             @SelectedRows int selection) {
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 09afedb..a92682a 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
@@ -1116,11 +1116,16 @@
     /**
      * Update whether we should show the empty shade view (no notifications in the shade).
      * If so, send the update to our view.
+     *
+     * When in split mode, notifications are always visible regardless of the state of the
+     * QuickSettings panel. That being the case, empty view is always shown if the other conditions
+     * are true.
      */
     public void updateShowEmptyShadeView() {
         mShowEmptyShadeView = mBarState != KEYGUARD
-                && !mView.isQsExpanded()
+                && (!mView.isQsExpanded() || mView.isUsingSplitNotificationShade())
                 && mView.getVisibleNotificationCount() == 0;
+
         mView.updateEmptyShadeView(
                 mShowEmptyShadeView,
                 mZenModeController.areNotificationsHiddenInShade());
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 1a2b989..349830f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -23,6 +23,8 @@
 import static androidx.constraintlayout.widget.ConstraintSet.START;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
+import static com.android.keyguard.KeyguardClockSwitch.LARGE;
+import static com.android.keyguard.KeyguardClockSwitch.SMALL;
 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
@@ -1243,7 +1245,14 @@
             updateClockAppearance();
         }
         if (!onKeyguard) {
-            stackScrollerPadding = getUnlockedStackScrollerPadding();
+            if (mShouldUseSplitNotificationShade) {
+                // Quick settings are not on the top of the notifications
+                // when in split shade mode (they are on the left side),
+                // so we should not add a padding for them
+                stackScrollerPadding = 0;
+            } else {
+                stackScrollerPadding = getUnlockedStackScrollerPadding();
+            }
         } else {
             stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
         }
@@ -1264,7 +1273,11 @@
         boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
         final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
                 .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
-        mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
+        if (hasVisibleNotifications && !mShouldUseSplitNotificationShade) {
+            mKeyguardStatusViewController.displayClock(SMALL);
+        } else {
+            mKeyguardStatusViewController.displayClock(LARGE);
+        }
         int userIconHeight = mKeyguardQsUserSwitchController != null
                 ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
         float expandedFraction =
@@ -2239,8 +2252,9 @@
 
     private void updateQSExpansionEnabledAmbient() {
         final float scrollRangeToTop = mAmbientState.getTopPadding() - mQuickQsOffsetHeight;
-        mQsExpansionEnabledAmbient =
-                mAmbientState.getScrollY() <= scrollRangeToTop && !mAmbientState.isShadeOpening();
+        mQsExpansionEnabledAmbient = mShouldUseSplitNotificationShade
+                || (mAmbientState.getScrollY() <= scrollRangeToTop
+                && !mAmbientState.isShadeOpening());
         setQsExpansionEnabled();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 98fb6f3..ae36e1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -437,7 +437,8 @@
             if (cb != null) {
                 cb.onStateChanged(mCurrentState.mKeyguardShowing,
                         mCurrentState.mKeyguardOccluded,
-                        mCurrentState.mBouncerShowing);
+                        mCurrentState.mBouncerShowing,
+                        mCurrentState.mDozing);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cfcea96..44ed279 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -359,21 +359,7 @@
         mAnimateChange = state.getAnimateChange();
         mAnimationDuration = state.getAnimationDuration();
 
-        mInFrontTint = state.getFrontTint();
-        mBehindTint = state.getBehindTint();
-        mNotificationsTint = state.getNotifTint();
-        mBubbleTint = state.getBubbleTint();
-
-        mInFrontAlpha = state.getFrontAlpha();
-        mBehindAlpha = state.getBehindAlpha();
-        mBubbleAlpha = state.getBubbleAlpha();
-        mNotificationsAlpha = state.getNotifAlpha();
-        if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
-            throw new IllegalStateException("Scrim opacity is NaN for state: " + state + ", front: "
-                    + mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
-                    + mNotificationsAlpha);
-        }
-        applyStateToAlpha();
+        applyState();
 
         // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
         // We need to disable focus otherwise AOD would end up with a gray overlay.
@@ -637,7 +623,19 @@
         }
     }
 
-    private void applyStateToAlpha() {
+    private void applyState() {
+        mInFrontTint = mState.getFrontTint();
+        mBehindTint = mState.getBehindTint();
+        mNotificationsTint = mState.getNotifTint();
+        mBubbleTint = mState.getBubbleTint();
+
+        mInFrontAlpha = mState.getFrontAlpha();
+        mBehindAlpha = mState.getBehindAlpha();
+        mBubbleAlpha = mState.getBubbleAlpha();
+        mNotificationsAlpha = mState.getNotifAlpha();
+
+        assertAlphasValid();
+
         if (!mExpansionAffectsAlpha) {
             return;
         }
@@ -695,6 +693,11 @@
                 mBehindTint = behindTint;
             }
         }
+
+        assertAlphasValid();
+    }
+
+    private void assertAlphasValid() {
         if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
             throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
                     + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
@@ -734,7 +737,7 @@
 
 
     private void applyAndDispatchState() {
-        applyStateToAlpha();
+        applyState();
         if (mUpdatePending) {
             return;
         }
@@ -1203,6 +1206,7 @@
         pw.println(" ScrimController: ");
         pw.print("  state: ");
         pw.println(mState);
+        pw.println("    mClipQsScrim = " + mState.mClipQsScrim);
 
         pw.print("  frontScrim:");
         pw.print(" viewAlpha=");
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 e846399..bc0a7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -931,6 +931,9 @@
             mStatusBar.setBouncerShowing(bouncerShowing);
         }
 
+        if (occluded != mLastOccluded || mFirstUpdate) {
+            mKeyguardUpdateManager.onKeyguardOccludedChanged(occluded);
+        }
         if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
             mKeyguardUpdateManager.onKeyguardVisibilityChanged(showing && !occluded);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index f33ff27..ac43b67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -16,5 +16,6 @@
 package com.android.systemui.statusbar.phone;
 
 public interface StatusBarWindowCallback {
-    void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing);
+    void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
+            boolean isDozing);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 9a25a70..3d3b58a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -34,6 +36,7 @@
 import android.util.Log;
 import android.view.Gravity;
 import android.view.IWindowManager;
+import android.view.Surface;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
@@ -118,21 +121,7 @@
         // Now that the status bar window encompasses the sliding panel and its
         // translucent backdrop, the entire thing is made TRANSLUCENT and is
         // hardware-accelerated.
-        mLp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                mBarHeight,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                PixelFormat.TRANSLUCENT);
-        mLp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
-        mLp.token = new Binder();
-        mLp.gravity = Gravity.TOP;
-        mLp.setFitInsetsTypes(0 /* types */);
-        mLp.setTitle("StatusBar");
-        mLp.packageName = mContext.getPackageName();
-        mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
 
         mWindowManager.addView(mStatusBarView, mLp);
         mLpChanged.copyFrom(mLp);
@@ -141,6 +130,63 @@
         calculateStatusBarLocationsForAllRotations();
     }
 
+    private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
+        WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
+        lp.paramsForRotation = new WindowManager.LayoutParams[4];
+        for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+            lp.paramsForRotation[rot] = getBarLayoutParamsForRotation(rot);
+        }
+        return lp;
+    }
+
+    private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
+        int height = mBarHeight;
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+            int defaultAndUpsideDownHeight;
+            int theOtherHeight;
+            if (displayBounds.width() > displayBounds.height()) {
+                defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.status_bar_height_landscape);
+                theOtherHeight = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.status_bar_height_portrait);
+            } else {
+                defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.status_bar_height_portrait);
+                theOtherHeight = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.status_bar_height_landscape);
+            }
+            switch (rotation) {
+                case ROTATION_UNDEFINED:
+                case Surface.ROTATION_0:
+                case Surface.ROTATION_180:
+                    height = defaultAndUpsideDownHeight;
+                    break;
+                case Surface.ROTATION_90:
+                case Surface.ROTATION_270:
+                    height = theOtherHeight;
+                    break;
+            }
+        }
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.MATCH_PARENT,
+                height,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+        lp.token = new Binder();
+        lp.gravity = Gravity.TOP;
+        lp.setFitInsetsTypes(0 /* types */);
+        lp.setTitle("StatusBar");
+        lp.packageName = mContext.getPackageName();
+        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        return lp;
+
+    }
+
     private void calculateStatusBarLocationsForAllRotations() {
         Rect[] bounds = new Rect[4];
         bounds[0] = mContentInsetsProvider
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index b18dfd2..ff3fed6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -72,11 +72,10 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -151,7 +150,9 @@
         @UiEvent(doc = "User sent data through the notification remote input view")
         NOTIFICATION_REMOTE_INPUT_SEND(797),
         @UiEvent(doc = "Failed attempt to send data through the notification remote input view")
-        NOTIFICATION_REMOTE_INPUT_FAILURE(798);
+        NOTIFICATION_REMOTE_INPUT_FAILURE(798),
+        @UiEvent(doc = "User attached an image to the remote input view")
+        NOTIFICATION_REMOTE_INPUT_ATTACH_IMAGE(825);
 
         private final int mId;
         NotificationRemoteInputEvent(int id) {
@@ -282,7 +283,8 @@
         });
     }
 
-    private void setAttachment(ContentInfo item) {
+    @VisibleForTesting
+    protected void setAttachment(ContentInfo item) {
         if (mEntry.remoteInputAttachment != null && mEntry.remoteInputAttachment != item) {
             // We need to release permissions when sending the attachment to the target
             // app or if it is deleted by the user. When sending to the target app, we
@@ -308,6 +310,10 @@
             attachment.setVisibility(GONE);
         } else {
             attachment.setVisibility(VISIBLE);
+            mUiEventLogger.logWithInstanceId(
+                    NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_ATTACH_IMAGE,
+                    mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
+                    mEntry.getSbn().getInstanceId());
         }
         updateSendButton();
     }
@@ -411,8 +417,6 @@
                 mEntry.getSbn().getPackageName(),
                 mEntry.getSbn().getUser().getIdentifier());
 
-        MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_SEND,
-                mEntry.getSbn().getPackageName());
         mUiEventLogger.logWithInstanceId(
                 NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_SEND,
                 mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
@@ -421,8 +425,6 @@
             mPendingIntent.send(mContext, 0, intent);
         } catch (PendingIntent.CanceledException e) {
             Log.i(TAG, "Unable to send remote input result", e);
-            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_FAIL,
-                    mEntry.getSbn().getPackageName());
             mUiEventLogger.logWithInstanceId(
                     NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_FAILURE,
                     mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
@@ -499,8 +501,6 @@
         mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false);
 
         if (logClose) {
-            MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
-                    mEntry.getSbn().getPackageName());
             mUiEventLogger.logWithInstanceId(
                     NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_CLOSE,
                     mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
@@ -582,8 +582,6 @@
     }
 
     public void focus() {
-        MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_OPEN,
-                mEntry.getSbn().getPackageName());
         mUiEventLogger.logWithInstanceId(
                 NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_OPEN,
                 mEntry.getSbn().getUid(), mEntry.getSbn().getPackageName(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 14190d8..85dcd13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -23,6 +23,7 @@
 
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.IActivityTaskManager;
 import android.content.BroadcastReceiver;
@@ -70,9 +71,11 @@
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.user.CreateUserActivity;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -103,9 +106,12 @@
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
     protected final Context mContext;
+    protected final UserTracker mUserTracker;
     protected final UserManager mUserManager;
+    private final ContentObserver mSettingsObserver;
     private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
-    private final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
+    @VisibleForTesting
+    final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
     private final KeyguardStateController mKeyguardStateController;
     protected final Handler mHandler;
     private final ActivityStarter mActivityStarter;
@@ -114,15 +120,18 @@
     private final IActivityTaskManager mActivityTaskManager;
 
     private ArrayList<UserRecord> mUsers = new ArrayList<>();
-    private Dialog mExitGuestDialog;
-    private Dialog mAddUserDialog;
+    @VisibleForTesting
+    AlertDialog mExitGuestDialog;
+    @VisibleForTesting
+    Dialog mAddUserDialog;
     private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
     private boolean mResumeUserOnGuestLogout = true;
     private boolean mSimpleUserSwitcher;
     // When false, there won't be any visual affordance to add a new user from the keyguard even if
     // the user is unlocked
     private boolean mAddUsersFromLockScreen;
-    private boolean mPauseRefreshUsers;
+    @VisibleForTesting
+    boolean mPauseRefreshUsers;
     private int mSecondaryUser = UserHandle.USER_NULL;
     private Intent mSecondaryUserServiceIntent;
     private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
@@ -134,6 +143,8 @@
 
     @Inject
     public UserSwitcherController(Context context,
+            UserManager userManager,
+            UserTracker userTracker,
             KeyguardStateController keyguardStateController,
             @Main Handler handler,
             ActivityStarter activityStarter,
@@ -142,13 +153,16 @@
             TelephonyListenerManager telephonyListenerManager,
             IActivityTaskManager activityTaskManager,
             UserDetailAdapter userDetailAdapter,
+            SecureSettings secureSettings,
             @UiBackground Executor uiBgExecutor) {
         mContext = context;
+        mUserTracker = userTracker;
         mBroadcastDispatcher = broadcastDispatcher;
         mTelephonyListenerManager = telephonyListenerManager;
         mActivityTaskManager = activityTaskManager;
         mUiEventLogger = uiEventLogger;
-        mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(this, mUiEventLogger);
+        mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
+                this, mUserTracker, mUiEventLogger, secureSettings);
         mUserDetailAdapter = userDetailAdapter;
         mUiBgExecutor = uiBgExecutor;
         if (!UserManager.isGuestUserEphemeral()) {
@@ -160,7 +174,7 @@
         mKeyguardStateController = keyguardStateController;
         mHandler = handler;
         mActivityStarter = activityStarter;
-        mUserManager = UserManager.get(context);
+        mUserManager = userManager;
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -179,6 +193,14 @@
         mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
                 PERMISSION_SELF, null /* scheduler */);
 
+        mSettingsObserver = new ContentObserver(mHandler) {
+            public void onChange(boolean selfChange) {
+                mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
+                mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
+                refreshUsers(UserHandle.USER_NULL);
+            };
+        };
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
                 mSettingsObserver);
@@ -240,11 +262,11 @@
                     return null;
                 }
                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
-                int currentId = ActivityManager.getCurrentUser();
+                int currentId = mUserTracker.getUserId();
                 // Check user switchability of the foreground user since SystemUI is running in
                 // User 0
                 boolean canSwitchUsers = mUserManager.getUserSwitchability(
-                        UserHandle.of(ActivityManager.getCurrentUser())) == SWITCHABILITY_STATUS_OK;
+                        UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK;
                 UserInfo currentUserInfo = null;
                 UserRecord guestRecord = null;
 
@@ -372,7 +394,7 @@
     }
 
     public void logoutCurrentUser() {
-        int currentUser = ActivityManager.getCurrentUser();
+        int currentUser = mUserTracker.getUserId();
         if (currentUser != UserHandle.USER_SYSTEM) {
             pauseRefreshUsers();
             ActivityManager.logoutCurrentUser();
@@ -384,7 +406,7 @@
             Log.w(TAG, "User " + userId + " could not removed.");
             return;
         }
-        if (ActivityManager.getCurrentUser() == userId) {
+        if (mUserTracker.getUserId() == userId) {
             switchToUserId(UserHandle.USER_SYSTEM);
         }
         if (mUserManager.removeUser(userId)) {
@@ -392,7 +414,8 @@
         }
     }
 
-    private void onUserListItemClicked(UserRecord record) {
+    @VisibleForTesting
+    void onUserListItemClicked(UserRecord record) {
         int id;
         if (record.isGuest && record.info == null) {
             // No guest user. Create one.
@@ -410,7 +433,7 @@
             id = record.info.id;
         }
 
-        int currUserId = ActivityManager.getCurrentUser();
+        int currUserId = mUserTracker.getUserId();
         if (currUserId == id) {
             if (record.isGuest) {
                 showExitGuestDialog(id);
@@ -561,15 +584,6 @@
         }
     };
 
-    private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
-        public void onChange(boolean selfChange) {
-            mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
-            mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
-            refreshUsers(UserHandle.USER_NULL);
-        };
-    };
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("UserSwitcherController state:");
@@ -628,13 +642,7 @@
      * UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
      */
     public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
-        UserInfo currentUser;
-        try {
-            currentUser = ActivityManager.getService().getCurrentUser();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't remove guest because ActivityManager is dead");
-            return;
-        }
+        UserInfo currentUser = mUserTracker.getUserInfo();
         if (currentUser.id != guestUserId) {
             Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
                     + " is not current user (" + currentUser.id + ")");
@@ -831,9 +839,9 @@
 
     private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
         EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
-                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
+                UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId());
         if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
-                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
+                UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) {
             record.isDisabledByAdmin = true;
             record.enforcedAdmin = admin;
         } else {
@@ -1040,7 +1048,8 @@
         }
     }
 
-    private final class AddUserDialog extends SystemUIDialog implements
+    @VisibleForTesting
+    final class AddUserDialog extends SystemUIDialog implements
             DialogInterface.OnClickListener {
 
         public AddUserDialog(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 11ddbd0..4738ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -325,6 +325,11 @@
 
         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
 
+        // All wallpaper color and keyguard logic only applies when Monet is enabled.
+        if (!mIsMonetEnabled) {
+            return;
+        }
+
         // Upon boot, make sure we have the most up to date colors
         Runnable updateColors = () -> {
             WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 5de7846..9446732 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -104,6 +104,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
+import com.android.internal.view.RotationPolicy;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
@@ -400,7 +401,9 @@
         mDialog.setCanceledOnTouchOutside(true);
         mDialog.setOnShowListener(dialog -> {
             mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
-            if (!isLandscape()) mDialogView.setTranslationX(mDialogView.getWidth() / 2.0f);
+            if (!shouldSlideInVolumeTray()) {
+                mDialogView.setTranslationX(mDialogView.getWidth() / 2.0f);
+            }
             mDialogView.setAlpha(0);
             mDialogView.animate()
                     .alpha(1)
@@ -587,6 +590,10 @@
         return (int) (alpha * 255);
     }
 
+    private boolean shouldSlideInVolumeTray() {
+        return mContext.getDisplay().getRotation() != RotationPolicy.NATURAL_ROTATION;
+    }
+
     private boolean isLandscape() {
         return mContext.getResources().getConfiguration().orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
@@ -1320,7 +1327,7 @@
 
                     hideRingerDrawer();
                 }, 50));
-        if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2.0f);
+        if (!shouldSlideInVolumeTray()) animator.translationX(mDialogView.getWidth() / 2.0f);
         animator.start();
         checkODICaptionsTooltip(true);
         mController.notifyVisible(false);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 2216a91..3be1d3c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -38,6 +38,7 @@
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.PipTransitionState;
 import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.tv.TvPipController;
 import com.android.wm.shell.pip.tv.TvPipMenuController;
@@ -144,10 +145,17 @@
 
     @WMSingleton
     @Provides
+    static PipTransitionState providePipTransitionState() {
+        return new PipTransitionState();
+    }
+
+    @WMSingleton
+    @Provides
     static PipTaskOrganizer providePipTaskOrganizer(Context context,
             TvPipMenuController tvPipMenuController,
             SyncTransactionQueue syncTransactionQueue,
             PipBoundsState pipBoundsState,
+            PipTransitionState pipTransitionState,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipAnimationController pipAnimationController,
             PipTransitionController pipTransitionController,
@@ -157,7 +165,7 @@
             PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
             @ShellMainThread ShellExecutor mainExecutor) {
         return new PipTaskOrganizer(context,
-                syncTransactionQueue, pipBoundsState, pipBoundsAlgorithm,
+                syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
                 tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
                 pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
                 shellTaskOrganizer, mainExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index bc956dc..f2db4f1 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -64,6 +64,7 @@
 import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -104,7 +105,8 @@
 
     // Shell interfaces
     private final Optional<Pip> mPipOptional;
-    private final Optional<LegacySplitScreen> mSplitScreenOptional;
+    private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
+    private final Optional<SplitScreen> mSplitScreenOptional;
     private final Optional<OneHanded> mOneHandedOptional;
     private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
     private final Optional<ShellCommandHandler> mShellCommandHandler;
@@ -120,6 +122,7 @@
     private final Executor mSysUiMainExecutor;
 
     private boolean mIsSysUiStateValid;
+    private KeyguardUpdateMonitorCallback mLegacySplitScreenKeyguardCallback;
     private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
     private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
     private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
@@ -128,7 +131,8 @@
     @Inject
     public WMShell(Context context,
             Optional<Pip> pipOptional,
-            Optional<LegacySplitScreen> splitScreenOptional,
+            Optional<LegacySplitScreen> legacySplitScreenOptional,
+            Optional<SplitScreen> splitScreenOptional,
             Optional<OneHanded> oneHandedOptional,
             Optional<HideDisplayCutout> hideDisplayCutoutOptional,
             Optional<ShellCommandHandler> shellCommandHandler,
@@ -149,6 +153,7 @@
         mScreenLifecycle = screenLifecycle;
         mSysUiState = sysUiState;
         mPipOptional = pipOptional;
+        mLegacySplitScreenOptional = legacySplitScreenOptional;
         mSplitScreenOptional = splitScreenOptional;
         mOneHandedOptional = oneHandedOptional;
         mHideDisplayCutoutOptional = hideDisplayCutoutOptional;
@@ -165,6 +170,7 @@
         mProtoTracer.add(this);
         mCommandQueue.addCallback(this);
         mPipOptional.ifPresent(this::initPip);
+        mLegacySplitScreenOptional.ifPresent(this::initLegacySplitScreen);
         mSplitScreenOptional.ifPresent(this::initSplitScreen);
         mOneHandedOptional.ifPresent(this::initOneHanded);
         mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
@@ -218,8 +224,8 @@
     }
 
     @VisibleForTesting
-    void initSplitScreen(LegacySplitScreen legacySplitScreen) {
-        mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+    void initLegacySplitScreen(LegacySplitScreen legacySplitScreen) {
+        mLegacySplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
             @Override
             public void onKeyguardVisibilityChanged(boolean showing) {
                 // Hide the divider when keyguard is showing. Even though keyguard/statusbar is
@@ -229,6 +235,17 @@
                 legacySplitScreen.onKeyguardVisibilityChanged(showing);
             }
         };
+        mKeyguardUpdateMonitor.registerCallback(mLegacySplitScreenKeyguardCallback);
+    }
+
+    @VisibleForTesting
+    void initSplitScreen(SplitScreen splitScreen) {
+        mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+            @Override
+            public void onKeyguardOccludedChanged(boolean occluded) {
+                splitScreen.onKeyguardOccludedChanged(occluded);
+            }
+        };
         mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 6ef7450..7e733a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -194,11 +194,12 @@
             ShellTaskOrganizer organizer,
             DisplayController displayController,
             @ShellMainThread ShellExecutor mainExecutor,
-            @ShellMainThread Handler mainHandler) {
+            @ShellMainThread Handler mainHandler,
+            SyncTransactionQueue syncQueue) {
         return Optional.of(BubbleController.create(context, null /* synchronizer */,
                 floatingContentCoordinator, statusBarService, windowManager,
                 windowManagerShellWrapper, launcherApps, taskStackListener,
-                uiEventLogger, organizer, displayController, mainExecutor, mainHandler));
+                uiEventLogger, organizer, displayController, mainExecutor, mainHandler, syncQueue));
     }
 
     //
@@ -424,8 +425,9 @@
     @Provides
     static TaskViewFactoryController provideTaskViewFactoryController(
             ShellTaskOrganizer shellTaskOrganizer,
-            @ShellMainThread ShellExecutor mainExecutor) {
-        return new TaskViewFactoryController(shellTaskOrganizer, mainExecutor);
+            @ShellMainThread ShellExecutor mainExecutor,
+            SyncTransactionQueue syncQueue) {
+        return new TaskViewFactoryController(shellTaskOrganizer, mainExecutor, syncQueue);
     }
 
     //
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 36fd9be..be7813e 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -48,6 +48,7 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransition;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.PipTransitionState;
 import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 import com.android.wm.shell.pip.phone.PipAppOpsListener;
@@ -184,8 +185,15 @@
 
     @WMSingleton
     @Provides
+    static PipTransitionState providePipTransitionState() {
+        return new PipTransitionState();
+    }
+
+    @WMSingleton
+    @Provides
     static PipTaskOrganizer providePipTaskOrganizer(Context context,
             SyncTransactionQueue syncTransactionQueue,
+            PipTransitionState pipTransitionState,
             PipBoundsState pipBoundsState,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PhonePipMenuController menuPhoneController,
@@ -197,7 +205,7 @@
             PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
             @ShellMainThread ShellExecutor mainExecutor) {
         return new PipTaskOrganizer(context,
-                syncTransactionQueue, pipBoundsState, pipBoundsAlgorithm,
+                syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
                 menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
                 pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
                 shellTaskOrganizer, mainExecutor);
@@ -215,8 +223,9 @@
     static PipTransitionController providePipTransitionController(Context context,
             Transitions transitions, ShellTaskOrganizer shellTaskOrganizer,
             PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
-            PipBoundsState pipBoundsState, PhonePipMenuController pipMenuController) {
-        return new PipTransition(context, pipBoundsState, pipMenuController,
+            PipBoundsState pipBoundsState, PipTransitionState pipTransitionState,
+            PhonePipMenuController pipMenuController) {
+        return new PipTransition(context, pipBoundsState, pipTransitionState, pipMenuController,
                 pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 10ed1d7..ce02b83 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -19,6 +19,9 @@
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
+import static com.android.keyguard.KeyguardClockSwitch.LARGE;
+import static com.android.keyguard.KeyguardClockSwitch.SMALL;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
@@ -247,4 +250,36 @@
 
         verify(plugin).setStyle(style);
     }
+
+    @Test
+    public void switchingToBigClock_makesSmallClockDisappear() {
+        mKeyguardClockSwitch.switchToClock(LARGE);
+
+        mKeyguardClockSwitch.mClockInAnim.end();
+        mKeyguardClockSwitch.mClockOutAnim.end();
+
+        assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1);
+        assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE);
+        assertThat(mClockFrame.getAlpha()).isEqualTo(0);
+    }
+
+    @Test
+    public void switchingToSmallClock_makesBigClockDisappear() {
+        mKeyguardClockSwitch.switchToClock(SMALL);
+
+        mKeyguardClockSwitch.mClockInAnim.end();
+        mKeyguardClockSwitch.mClockOutAnim.end();
+
+        assertThat(mClockFrame.getAlpha()).isEqualTo(1);
+        assertThat(mClockFrame.getVisibility()).isEqualTo(VISIBLE);
+        // only big clock is removed at switch
+        assertThat(mLargeClockFrame.getParent()).isNull();
+        assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0);
+    }
+
+    @Test
+    public void switchingToBigClock_returnsTrueOnlyWhenItWasNotVisibleBefore() {
+        assertThat(mKeyguardClockSwitch.switchToClock(LARGE)).isTrue();
+        assertThat(mKeyguardClockSwitch.switchToClock(LARGE)).isFalse();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index ca857c5..64bdc2e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -19,11 +19,13 @@
 import static android.view.WindowInsets.Type.ime;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 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.times;
 import static org.mockito.Mockito.verify;
@@ -33,6 +35,7 @@
 import android.content.res.Resources;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.MotionEvent;
 import android.view.WindowInsetsController;
 
 import androidx.test.filters.SmallTest;
@@ -43,6 +46,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -58,6 +62,7 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
+    private static final int VIEW_WIDTH = 1600;
 
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
@@ -100,6 +105,8 @@
     private EmergencyButtonController mEmergencyButtonController;
     @Mock
     private Resources mResources;
+    @Mock
+    private FalsingCollector mFalsingCollector;
     private Configuration mConfiguration;
 
     private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@@ -112,7 +119,9 @@
         mConfiguration.setToDefaults(); // Defaults to ORIENTATION_UNDEFINED.
 
         when(mResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mView.getContext()).thenReturn(mContext);
         when(mView.getResources()).thenReturn(mResources);
+        when(mView.getWidth()).thenReturn(VIEW_WIDTH);
         when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
                 .thenReturn(mAdminSecondaryLockScreenController);
         when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
@@ -131,7 +140,7 @@
                 mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
                 mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
                 mKeyguardStateController, mKeyguardSecurityViewFlipperController,
-                mConfigurationController)
+                mConfigurationController, mFalsingCollector)
                 .create(mSecurityCallback);
     }
 
@@ -169,18 +178,156 @@
     public void onResourcesUpdate_callsThroughOnRotationChange() {
         // Rotation is the same, shouldn't cause an update
         mKeyguardSecurityContainerController.updateResources();
-        verify(mView, times(0)).updateLayoutForSecurityMode(any());
+        verify(mView, times(0)).setOneHandedMode(anyBoolean());
 
         // Update rotation. Should trigger update
         mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
 
         mKeyguardSecurityContainerController.updateResources();
-        verify(mView, times(1)).updateLayoutForSecurityMode(any());
+        verify(mView, times(1)).setOneHandedMode(anyBoolean());
     }
 
     @Test
-    public void updateKeyguardPosition_callsThroughToView() {
+    public void updateKeyguardPosition_callsThroughToViewInOneHandedMode() {
+        when(mView.isOneHandedMode()).thenReturn(true);
+        mKeyguardSecurityContainerController.updateKeyguardPosition(VIEW_WIDTH / 3f);
+        verify(mView).setOneHandedModeLeftAligned(true, false);
+
+        mKeyguardSecurityContainerController.updateKeyguardPosition((VIEW_WIDTH / 3f) * 2);
+        verify(mView).setOneHandedModeLeftAligned(false, false);
+    }
+
+    @Test
+    public void updateKeyguardPosition_ignoredInTwoHandedMode() {
+        when(mView.isOneHandedMode()).thenReturn(false);
         mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f);
-        verify(mView).updateKeyguardPosition(1.0f);
+        verify(mView, never()).setOneHandedModeLeftAligned(anyBoolean(), anyBoolean());
+    }
+
+    private void touchDownLeftSide() {
+        mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent(
+                MotionEvent.obtain(
+                        /* downTime= */0,
+                        /* eventTime= */0,
+                        MotionEvent.ACTION_DOWN,
+                        /* x= */VIEW_WIDTH / 3f,
+                        /* y= */0,
+                        /* metaState= */0));
+    }
+
+    private void touchDownRightSide() {
+        mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent(
+                MotionEvent.obtain(
+                        /* downTime= */0,
+                        /* eventTime= */0,
+                        MotionEvent.ACTION_DOWN,
+                        /* x= */(VIEW_WIDTH / 3f) * 2,
+                        /* y= */0,
+                        /* metaState= */0));
+    }
+
+    @Test
+    public void onInterceptTap_inhibitsFalsingInOneHandedMode() {
+        when(mView.isOneHandedMode()).thenReturn(true);
+        when(mView.isOneHandedModeLeftAligned()).thenReturn(true);
+
+        touchDownLeftSide();
+        verify(mFalsingCollector, never()).avoidGesture();
+
+        // Now on the right.
+        touchDownRightSide();
+        verify(mFalsingCollector).avoidGesture();
+
+        // Move and re-test
+        reset(mFalsingCollector);
+        when(mView.isOneHandedModeLeftAligned()).thenReturn(false);
+
+        // On the right...
+        touchDownRightSide();
+        verify(mFalsingCollector, never()).avoidGesture();
+
+        touchDownLeftSide();
+        verify(mFalsingCollector).avoidGesture();
+    }
+
+    @Test
+    public void showSecurityScreen_oneHandedMode_bothFlagsDisabled_noOneHandedMode() {
+        setUpKeyguardFlags(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */false);
+
+        when(mKeyguardSecurityViewFlipperController.getSecurityView(
+                eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
+                .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
+
+        mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
+        verify(mView).setOneHandedMode(false);
+    }
+
+    @Test
+    public void showSecurityScreen_oneHandedMode_deviceFlagDisabled_noOneHandedMode() {
+        setUpKeyguardFlags(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */true);
+
+        when(mKeyguardSecurityViewFlipperController.getSecurityView(
+                eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
+                .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
+
+        mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
+        verify(mView).setOneHandedMode(false);
+    }
+
+    @Test
+    public void showSecurityScreen_oneHandedMode_sysUiFlagDisabled_noOneHandedMode() {
+        setUpKeyguardFlags(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */false);
+
+        when(mKeyguardSecurityViewFlipperController.getSecurityView(
+                eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
+                .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
+
+        mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
+        verify(mView).setOneHandedMode(false);
+    }
+
+    @Test
+    public void showSecurityScreen_oneHandedMode_bothFlagsEnabled_oneHandedMode() {
+        setUpKeyguardFlags(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */true);
+
+        when(mKeyguardSecurityViewFlipperController.getSecurityView(
+                eq(SecurityMode.Pattern), any(KeyguardSecurityCallback.class)))
+                .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
+
+        mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
+        verify(mView).setOneHandedMode(true);
+    }
+
+    @Test
+    public void showSecurityScreen_twoHandedMode_bothFlagsEnabled_noOneHandedMode() {
+        setUpKeyguardFlags(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */true);
+
+        when(mKeyguardSecurityViewFlipperController.getSecurityView(
+                eq(SecurityMode.Password), any(KeyguardSecurityCallback.class)))
+                .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
+
+        mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
+        verify(mView).setOneHandedMode(false);
+    }
+
+    private void setUpKeyguardFlags(
+            boolean deviceConfigCanUseOneHandedKeyguard,
+            boolean sysuiResourceCanUseOneHandedKeyguard) {
+        when(mResources.getBoolean(
+                com.android.internal.R.bool.config_enableDynamicKeyguardPositioning))
+                .thenReturn(deviceConfigCanUseOneHandedKeyguard);
+        when(mResources.getBoolean(
+                R.bool.can_use_one_handed_bouncer))
+                .thenReturn(sysuiResourceCanUseOneHandedKeyguard);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index f5916e7..0276323 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -28,7 +28,6 @@
 import android.graphics.Insets;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.testing.TestableResources;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowInsets;
@@ -37,8 +36,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -57,11 +54,6 @@
     private static final int FAKE_MEASURE_SPEC =
             View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY);
 
-    private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN;
-    private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password;
-
-
-
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
 
@@ -90,45 +82,8 @@
     }
 
     @Test
-    public void onMeasure_usesFullWidthWithoutOneHandedMode() {
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */false,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
-                ONE_HANDED_SECURITY_MODE);
-
-        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-
-        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-    }
-
-    @Test
-    public void onMeasure_usesFullWidthWithDeviceFlagDisabled() {
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */false,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
-                ONE_HANDED_SECURITY_MODE);
-
-        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-    }
-
-    @Test
-    public void onMeasure_usesFullWidthWithSysUIFlagDisabled() {
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */true,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
-                ONE_HANDED_SECURITY_MODE);
-
-        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
-    }
-
-    @Test
-    public void onMeasure_usesHalfWidthWithFlagsEnabled() {
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */true,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
-                ONE_HANDED_SECURITY_MODE);
+    public void onMeasure_usesHalfWidthWithOneHandedModeEnabled() {
+        mKeyguardSecurityContainer.setOneHandedMode(/* oneHandedMode= */true);
 
         int halfWidthMeasureSpec =
                 View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY);
@@ -138,11 +93,8 @@
     }
 
     @Test
-    public void onMeasure_usesFullWidthForFullScreenIme() {
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */true,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
-                TWO_HANDED_SECURITY_MODE);
+    public void onMeasure_usesFullWidthWithOneHandedModeDisabled() {
+        mKeyguardSecurityContainer.setOneHandedMode(/* oneHandedMode= */false);
 
         mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
         verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
@@ -153,10 +105,7 @@
         int imeInsetAmount = 100;
         int systemBarInsetAmount = 10;
 
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */false,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
-                ONE_HANDED_SECURITY_MODE);
+        mKeyguardSecurityContainer.setOneHandedMode(/* oneHandedMode= */false);
 
         Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
         Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -180,10 +129,7 @@
         int imeInsetAmount = 0;
         int systemBarInsetAmount = 10;
 
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */false,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
-                ONE_HANDED_SECURITY_MODE);
+        mKeyguardSecurityContainer.setOneHandedMode(/* oneHandedMode= */false);
 
         Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
         Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -201,56 +147,41 @@
         verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec);
     }
 
-    private void setupForUpdateKeyguardPosition(SecurityMode securityMode) {
-        setUpKeyguard(
-                /* deviceConfigCanUseOneHandedKeyguard= */true,
-                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
-                securityMode);
+    private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
+        mKeyguardSecurityContainer.setOneHandedMode(oneHandedMode);
+        mKeyguardSecurityContainer.setOneHandedModeLeftAligned(true, false);
 
         mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
         mKeyguardSecurityContainer.layout(0, 0, SCREEN_WIDTH, SCREEN_WIDTH);
 
-        // Start off left-aligned. This should happen anyway, but just do this to ensure
-        // definitely move to the left.
-        mKeyguardSecurityContainer.updateKeyguardPosition(0.0f);
-
         // Clear any interactions with the mock so we know the interactions definitely come from the
         // below testing.
         reset(mSecurityViewFlipper);
     }
 
     @Test
-    public void updateKeyguardPosition_movesKeyguard() {
-        setupForUpdateKeyguardPosition(ONE_HANDED_SECURITY_MODE);
+    public void setIsLeftAligned_movesKeyguard() {
+        setupForUpdateKeyguardPosition(/* oneHandedMode= */ true);
 
-        mKeyguardSecurityContainer.updateKeyguardPosition((SCREEN_WIDTH / 4f) * 3f);
+        mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
+                /* leftAligned= */false, /* animate= */false);
         verify(mSecurityViewFlipper).setTranslationX(SCREEN_WIDTH / 2.0f);
 
-        mKeyguardSecurityContainer.updateKeyguardPosition(0.0f);
+        mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
+                /* leftAligned= */true, /* animate= */false);
         verify(mSecurityViewFlipper).setTranslationX(0.0f);
     }
 
     @Test
-    public void updateKeyguardPosition_doesntMoveTwoHandedKeyguard() {
-        setupForUpdateKeyguardPosition(TWO_HANDED_SECURITY_MODE);
+    public void setIsLeftAligned_doesntMoveTwoHandedKeyguard() {
+        setupForUpdateKeyguardPosition(/* oneHandedMode= */ false);
 
-        mKeyguardSecurityContainer.updateKeyguardPosition((SCREEN_WIDTH / 4f) * 3f);
+        mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
+                /* leftAligned= */false, /* animate= */false);
         verify(mSecurityViewFlipper, never()).setTranslationX(anyInt());
 
-        mKeyguardSecurityContainer.updateKeyguardPosition(0.0f);
+        mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
+                /* leftAligned= */true, /* animate= */false);
         verify(mSecurityViewFlipper, never()).setTranslationX(anyInt());
     }
-
-    private void setUpKeyguard(
-            boolean deviceConfigCanUseOneHandedKeyguard,
-            boolean sysuiResourceCanUseOneHandedKeyguard,
-            SecurityMode securityMode) {
-        TestableResources testableResources = mContext.getOrCreateTestableResources();
-        testableResources.addOverride(
-                com.android.internal.R.bool.config_enableDynamicKeyguardPositioning,
-                deviceConfigCanUseOneHandedKeyguard);
-        testableResources.addOverride(R.bool.can_use_one_handed_bouncer,
-                sysuiResourceCanUseOneHandedKeyguard);
-        mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
index 9621bed..8bb9d42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/TestableWindowManager.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.accessibility;
 
-import static android.view.WindowInsets.Type.systemGestures;
-
-import android.graphics.Insets;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.view.Display;
@@ -79,14 +76,11 @@
 
     @Override
     public WindowMetrics getCurrentWindowMetrics() {
-        final Insets systemGesturesInsets = Insets.of(0, 0, 0, 10);
-        final WindowInsets insets = new WindowInsets.Builder()
-                .setInsets(systemGestures(), systemGesturesInsets)
-                .build();
+        final WindowMetrics realMetrics = mWindowManager.getCurrentWindowMetrics();
         final WindowMetrics windowMetrics = new WindowMetrics(
-                mWindowBounds == null ? mWindowManager.getCurrentWindowMetrics().getBounds()
+                mWindowBounds == null ? realMetrics.getBounds()
                         : mWindowBounds,
-                mWindowInsets == null ? insets : mWindowInsets);
+                mWindowInsets == null ?  realMetrics.getWindowInsets() : mWindowInsets);
         return windowMetrics;
     }
 
@@ -106,10 +100,20 @@
         return (WindowManager.LayoutParams) mView.getLayoutParams();
     }
 
+    /**
+     * Sets the given window bounds to current window metrics.
+     *
+     * @param bounds the window bounds
+     */
     public void setWindowBounds(Rect bounds) {
         mWindowBounds = bounds;
     }
 
+    /**
+     * Sets the given window insets to the current window metics.
+     *
+     * @param insets the window insets.
+     */
     public void setWindowInsets(WindowInsets insets) {
         mWindowInsets = insets;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index f62069d..76cc7a0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.accessibility;
 
 import static android.view.Choreographer.FrameCallback;
+import static android.view.WindowInsets.Type.systemGestures;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
@@ -45,6 +46,8 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.SystemClock;
@@ -55,6 +58,7 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.View;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 
@@ -239,11 +243,13 @@
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
             mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE);
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
         });
     }
 
     @Test
-    public void onOrientationChanged_enabled_updateDisplayRotationAndLayout() {
+    public void onOrientationChanged_enabled_updateDisplayRotationAndCenterStayAtSamePosition() {
         final Display display = Mockito.spy(mContext.getDisplay());
         when(display.getRotation()).thenReturn(Surface.ROTATION_90);
         when(mContext.getDisplay()).thenReturn(display);
@@ -251,13 +257,22 @@
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                     Float.NaN);
         });
+        final PointF expectedCenter = new PointF(mWindowMagnificationController.getCenterY(),
+                mWindowMagnificationController.getCenterX());
+        final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+        // Rotate the window 90 degrees.
+        windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
+                windowBounds.right);
+        mWindowManager.setWindowBounds(windowBounds);
 
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
         });
 
         assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
-        // The first invocation is called when the surface is created.
+        final PointF actualCenter = new PointF(mWindowMagnificationController.getCenterX(),
+                mWindowMagnificationController.getCenterY());
+        assertEquals(expectedCenter, actualCenter);
         verify(mWindowManager, times(2)).updateViewLayout(any(), any());
     }
 
@@ -275,6 +290,33 @@
     }
 
     @Test
+    public void onScreenSizeChanged_enabledAtTheCenterOfScreen_keepSameWindowSizeRatio() {
+        // The default position is at the center of the screen.
+        final float expectedRatio = 0.5f;
+        final Rect testWindowBounds = new Rect(
+                mWindowManager.getCurrentWindowMetrics().getBounds());
+        testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
+                testWindowBounds.right + 100, testWindowBounds.bottom + 100);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+        mWindowManager.setWindowBounds(testWindowBounds);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+        });
+
+        // The ratio of center to window size should be the same.
+        assertEquals(expectedRatio,
+                mWindowMagnificationController.getCenterX() / testWindowBounds.width(),
+                0);
+        assertEquals(expectedRatio,
+                mWindowMagnificationController.getCenterY() / testWindowBounds.height(),
+                0);
+    }
+
+    @Test
     public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -419,9 +461,12 @@
     }
 
     @Test
-    public void moveWindowMagnificationToTheBottom_enabled_overlapFlagIsTrue() {
-        final WindowManager wm = mContext.getSystemService(WindowManager.class);
-        final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
+    public void moveWindowMagnificationToTheBottom_enabledWithGestureInset_overlapFlagIsTrue() {
+        final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+        final WindowInsets testInsets = new WindowInsets.Builder()
+                .setInsets(systemGestures(), Insets.of(0, 0, 0, 10))
+                .build();
+        mWindowManager.setWindowInsets(testInsets);
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                     Float.NaN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 578c2d9..32abbc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -104,7 +104,6 @@
     @Mock private IWindowManager mWindowManager;
     @Mock private Executor mBackgroundExecutor;
     @Mock private UiEventLogger mUiEventLogger;
-    @Mock private GlobalActionsInfoProvider mInfoProvider;
     @Mock private RingerModeTracker mRingerModeTracker;
     @Mock private RingerModeLiveData mRingerModeLiveData;
     @Mock private SysUiState mSysUiState;
@@ -151,7 +150,6 @@
                 mWindowManager,
                 mBackgroundExecutor,
                 mUiEventLogger,
-                mInfoProvider,
                 mRingerModeTracker,
                 mSysUiState,
                 mHandler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsInfoProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsInfoProviderTest.kt
deleted file mode 100644
index 302a8d3..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsInfoProviderTest.kt
+++ /dev/null
@@ -1,134 +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.google.android.systemui.globalactions
-
-import android.content.Context
-import android.content.SharedPreferences
-import android.content.res.Configuration
-import android.content.res.Resources
-import android.service.quickaccesswallet.QuickAccessWalletClient
-import android.testing.AndroidTestingRunner
-import android.view.ViewGroup
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.controls.controller.ControlsController
-import com.android.systemui.globalactions.GlobalActionsInfoProvider
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.SysuiTestCase
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.anyObject
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Mock
-import org.mockito.Mockito
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import org.mockito.Mockito.`when` as whenever
-
-private const val PREFERENCE = "global_actions_info_prefs"
-private const val KEY_VIEW_COUNT = "view_count"
-
-private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class GlobalActionsInfoProviderTest : SysuiTestCase() {
-
-    @Mock private lateinit var walletClient: QuickAccessWalletClient
-    @Mock private lateinit var controlsController: ControlsController
-    @Mock private lateinit var activityStarter: ActivityStarter
-    @Mock private lateinit var mockContext: Context
-    @Mock private lateinit var mockResources: Resources
-    @Mock private lateinit var sharedPrefs: SharedPreferences
-    @Mock private lateinit var sharedPrefsEditor: SharedPreferences.Editor
-
-    private lateinit var infoProvider: GlobalActionsInfoProvider
-
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-        mockContext = spy(context)
-        mockResources = spy(context.resources)
-        whenever(mockContext.resources).thenReturn(mockResources)
-        whenever(mockResources.getBoolean(R.bool.global_actions_show_change_info))
-                .thenReturn(true)
-        whenever(mockContext.getSharedPreferences(eq(PREFERENCE), anyInt()))
-                .thenReturn(sharedPrefs)
-        whenever(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
-        whenever(sharedPrefsEditor.putInt(anyString(), anyInt())).thenReturn(sharedPrefsEditor)
-        whenever(sharedPrefsEditor.putBoolean(anyString(), anyBoolean()))
-                .thenReturn(sharedPrefsEditor)
-
-        infoProvider = GlobalActionsInfoProvider(
-                mockContext,
-                walletClient,
-                controlsController,
-                activityStarter
-        )
-    }
-
-    @Test
-    fun testIsEligible_noCards() {
-        whenever(sharedPrefs.contains(eq(KEY_VIEW_COUNT))).thenReturn(false)
-        whenever(walletClient.isWalletFeatureAvailable).thenReturn(false)
-
-        assertFalse(infoProvider.shouldShowMessage())
-    }
-
-    @Test
-    fun testIsEligible_hasCards() {
-        whenever(sharedPrefs.contains(eq(KEY_VIEW_COUNT))).thenReturn(false)
-        whenever(walletClient.isWalletFeatureAvailable).thenReturn(true)
-
-        assertTrue(infoProvider.shouldShowMessage())
-    }
-
-    @Test
-    fun testNotEligible_shouldNotShow() {
-        whenever(mockResources.getBoolean(R.bool.global_actions_show_change_info))
-                .thenReturn(false)
-
-        assertFalse(infoProvider.shouldShowMessage())
-    }
-
-    @Test
-    fun testTooManyButtons_doesNotAdd() {
-        val configuration = Configuration()
-        configuration.orientation = Configuration.ORIENTATION_LANDSCAPE
-        whenever(mockResources.configuration).thenReturn(configuration)
-
-        val parent = mock(ViewGroup::class.java)
-        infoProvider.addPanel(mockContext, parent, 5, { })
-
-        verify(parent, never()).addView(anyObject(), anyInt())
-    }
-
-    @Test
-    fun testLimitTimesShown() {
-        whenever(sharedPrefs.getInt(eq(KEY_VIEW_COUNT), anyInt())).thenReturn(4)
-
-        assertFalse(infoProvider.shouldShowMessage())
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index d2527c6..e9a7c73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -81,6 +81,8 @@
     private NavigationBar mDefaultNavBar;
     private NavigationBar mSecondaryNavBar;
 
+    private CommandQueue mCommandQueue = mock(CommandQueue.class);
+
     private static final int SECONDARY_DISPLAY = 1;
 
     @Before
@@ -99,7 +101,7 @@
                         mock(StatusBarStateController.class),
                         mock(SysUiState.class),
                         mock(BroadcastDispatcher.class),
-                        mock(CommandQueue.class),
+                        mCommandQueue,
                         Optional.of(mock(Pip.class)),
                         Optional.of(mock(LegacySplitScreen.class)),
                         Optional.of(mock(Recents.class)),
@@ -112,6 +114,8 @@
                         mock(UiEventLogger.class),
                         mock(NavigationBarOverlayController.class),
                         mock(ConfigurationController.class),
+                        mock(NavigationBarA11yHelper.class),
+                        mock(TaskbarDelegate.class),
                         mock(UserTracker.class)));
         initializeNavigationBars();
     }
@@ -275,4 +279,9 @@
 
         verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
     }
+
+    @Test
+    public void test3ButtonTaskbarFlagDisabledNoRegister() {
+        verify(mCommandQueue, never()).addCallback(any(TaskbarDelegate.class));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
index eac68f6..b991976 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
@@ -31,9 +31,6 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-import com.android.systemui.navigationbar.RotationButton;
-import com.android.systemui.navigationbar.RotationButtonController;
 import com.android.systemui.statusbar.policy.RotationLockController;
 
 import org.junit.Before;
@@ -46,7 +43,6 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class NavigationBarRotationContextTest extends SysuiTestCase {
-    static final int RES_UNDEF = 0;
     static final int DEFAULT_ROTATE = 0;
 
     @Rule
@@ -66,7 +62,6 @@
         mRotationButtonController.setRotationButton(mRotationButton, (visibility) -> {});
         // Due to a mockito issue, only spy the object after setting the initial state
         mRotationButtonController = spy(mRotationButtonController);
-        final KeyButtonDrawable kbd = mock(KeyButtonDrawable.class);
         doReturn(view).when(mRotationButton).getCurrentView();
         doReturn(true).when(mRotationButton).acceptRotationProposal();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index a570675..c606a43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -280,6 +280,7 @@
                 mHandler,
                 mock(NavigationBarOverlayController.class),
                 mUiEventLogger,
+                mock(NavigationBarA11yHelper.class),
                 mock(UserTracker.class)));
     }
 
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
new file mode 100644
index 0000000..6ee2f20
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack;
+
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.metrics.LogMaker;
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollectorFake;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.media.KeyguardMediaController;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link NotificationStackScrollLayoutController}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
+
+    @Mock private NotificationGutsManager mNotificationGutsManager;
+    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
+    @Mock private TunerService mTunerService;
+    @Mock private DynamicPrivacyController mDynamicPrivacyController;
+    @Mock private ConfigurationController mConfigurationController;
+    @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
+    @Mock private ZenModeController mZenModeController;
+    @Mock private KeyguardMediaController mKeyguardMediaController;
+    @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
+    @Mock private KeyguardBypassController mKeyguardBypassController;
+    @Mock private SysuiColorExtractor mColorExtractor;
+    @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+    @Mock private MetricsLogger mMetricsLogger;
+    @Mock private Resources mResources;
+    @Mock(answer = Answers.RETURNS_SELF)
+    private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
+    @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
+    @Mock private StatusBar mStatusBar;
+    @Mock private ScrimController mScrimController;
+    @Mock private NotificationGroupManagerLegacy mLegacyGroupManager;
+    @Mock private SectionHeaderController mSilentHeaderController;
+    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private NotifPipeline mNotifPipeline;
+    @Mock private NotifCollection mNotifCollection;
+    @Mock private NotificationEntryManager mEntryManager;
+    @Mock private IStatusBarService mIStatusBarService;
+    @Mock private UiEventLogger mUiEventLogger;
+    @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+    @Mock private ForegroundServiceDismissalFeatureController mFgFeatureController;
+    @Mock private ForegroundServiceSectionController mFgServicesSectionController;
+    @Mock private ForegroundServiceDungeonView mForegroundServiceDungeonView;
+    @Mock private LayoutInflater mLayoutInflater;
+    @Mock private NotificationRemoteInputManager mRemoteInputManager;
+    @Mock private RemoteInputController mRemoteInputController;
+    @Mock private VisualStabilityManager mVisualStabilityManager;
+    @Mock private ShadeController mShadeController;
+
+    @Captor
+    private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
+
+    private NotificationStackScrollLayoutController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
+        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
+        when(mFgServicesSectionController.createView(mLayoutInflater))
+                .thenReturn(mForegroundServiceDungeonView);
+        when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
+
+        mController = new NotificationStackScrollLayoutController(
+                true,
+                mNotificationGutsManager,
+                mHeadsUpManager,
+                mNotificationRoundnessManager,
+                mTunerService,
+                mDynamicPrivacyController,
+                mConfigurationController,
+                mSysuiStatusBarStateController,
+                mKeyguardMediaController,
+                mKeyguardBypassController,
+                mZenModeController,
+                mColorExtractor,
+                mNotificationLockscreenUserManager,
+                mMetricsLogger,
+                new FalsingCollectorFake(),
+                new FalsingManagerFake(),
+                mResources,
+                mNotificationSwipeHelperBuilder,
+                mStatusBar,
+                mScrimController,
+                mLegacyGroupManager,
+                mLegacyGroupManager,
+                mSilentHeaderController,
+                mFeatureFlags,
+                mNotifPipeline,
+                mNotifCollection,
+                mEntryManager,
+                mLockscreenShadeTransitionController,
+                mIStatusBarService,
+                mUiEventLogger,
+                mFgFeatureController,
+                mFgServicesSectionController,
+                mLayoutInflater,
+                mRemoteInputManager,
+                mVisualStabilityManager,
+                mShadeController
+        );
+
+        when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
+    }
+
+    @Test
+    public void testAttach_viewAlreadyAttached() {
+        mController.attach(mNotificationStackScrollLayout);
+
+        verify(mConfigurationController).addCallback(
+                any(ConfigurationController.ConfigurationListener.class));
+    }
+    @Test
+    public void testAttach_viewAttachedAfterInit() {
+        when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(false);
+
+        mController.attach(mNotificationStackScrollLayout);
+
+        verify(mConfigurationController, never()).addCallback(
+                any(ConfigurationController.ConfigurationListener.class));
+
+        mController.mOnAttachStateChangeListener.onViewAttachedToWindow(
+                mNotificationStackScrollLayout);
+
+        verify(mConfigurationController).addCallback(
+                any(ConfigurationController.ConfigurationListener.class));
+    }
+
+    @Test
+    public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
+        mController.attach(mNotificationStackScrollLayout);
+        mController.mConfigurationListener.onDensityOrFontScaleChanged();
+        verify(mNotificationStackScrollLayout).reinflateViews();
+    }
+
+    @Test
+    public void testUpdateEmptyShadeView_notificationsVisible_zenHiding() {
+        when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mSysuiStatusBarStateController).addCallback(
+                mStateListenerArgumentCaptor.capture(), anyInt());
+        StatusBarStateController.StateListener stateListener =
+                mStateListenerArgumentCaptor.getValue();
+
+        setupShowEmptyShadeViewState(stateListener, true);
+        reset(mNotificationStackScrollLayout);
+        mController.updateShowEmptyShadeView();
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+                /* visible= */ true,
+                /* notifVisibleInShade= */ true);
+
+        setupShowEmptyShadeViewState(stateListener, false);
+        reset(mNotificationStackScrollLayout);
+        mController.updateShowEmptyShadeView();
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+                /* visible= */ false,
+                /* notifVisibleInShade= */ true);
+    }
+
+    @Test
+    public void testUpdateEmptyShadeView_notificationsHidden_zenNotHiding() {
+        when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mSysuiStatusBarStateController).addCallback(
+                mStateListenerArgumentCaptor.capture(), anyInt());
+        StatusBarStateController.StateListener stateListener =
+                mStateListenerArgumentCaptor.getValue();
+
+        setupShowEmptyShadeViewState(stateListener, true);
+        reset(mNotificationStackScrollLayout);
+        mController.updateShowEmptyShadeView();
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+                /* visible= */ true,
+                /* notifVisibleInShade= */ false);
+
+        setupShowEmptyShadeViewState(stateListener, false);
+        reset(mNotificationStackScrollLayout);
+        mController.updateShowEmptyShadeView();
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+                /* visible= */ false,
+                /* notifVisibleInShade= */ false);
+    }
+
+    @Test
+    public void testUpdateEmptyShadeView_splitShadeMode_alwaysShowEmptyView() {
+        when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mSysuiStatusBarStateController).addCallback(
+                mStateListenerArgumentCaptor.capture(), anyInt());
+        StatusBarStateController.StateListener stateListener =
+                mStateListenerArgumentCaptor.getValue();
+        when(mNotificationStackScrollLayout.isUsingSplitNotificationShade()).thenReturn(true);
+        stateListener.onStateChanged(SHADE);
+        mController.getView().removeAllViews();
+
+        mController.setQsExpanded(false);
+        reset(mNotificationStackScrollLayout);
+        mController.updateShowEmptyShadeView();
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+                /* visible= */ true,
+                /* notifVisibleInShade= */ false);
+
+        mController.setQsExpanded(true);
+        reset(mNotificationStackScrollLayout);
+        mController.updateShowEmptyShadeView();
+        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
+                /* visible= */ true,
+                /* notifVisibleInShade= */ false);
+    }
+
+    @Test
+    public void testOnUserChange_verifySensitiveProfile() {
+        when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+        ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
+                .forClass(UserChangedListener.class);
+
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mNotificationLockscreenUserManager)
+                .addUserChangedListener(userChangedCaptor.capture());
+        reset(mNotificationStackScrollLayout);
+
+        UserChangedListener changedListener = userChangedCaptor.getValue();
+        changedListener.onUserChanged(0);
+        verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+    }
+
+    @Test
+    public void testOnStatePostChange_verifyIfProfileIsPublic() {
+        when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
+
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mSysuiStatusBarStateController).addCallback(
+                mStateListenerArgumentCaptor.capture(), anyInt());
+
+        StatusBarStateController.StateListener stateListener =
+                mStateListenerArgumentCaptor.getValue();
+
+        stateListener.onStatePostChange();
+        verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
+    }
+
+    @Test
+    public void testOnMenuShownLogging() {
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+        when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+                MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+        ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+                ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
+                onMenuEventListenerArgumentCaptor.capture());
+
+        OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+        onMenuEventListener.onMenuShown(row);
+        verify(row.getEntry().getSbn()).getLogMaker();  // This writes most of the log data
+        verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
+                MetricsProto.MetricsEvent.TYPE_ACTION));
+    }
+
+    @Test
+    public void testOnMenuClickedLogging() {
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+        when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
+                MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+        ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
+                ArgumentCaptor.forClass(OnMenuEventListener.class);
+
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
+                onMenuEventListenerArgumentCaptor.capture());
+
+        OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
+
+        onMenuEventListener.onMenuClicked(row, 0, 0, mock(
+                NotificationMenuRowPlugin.MenuItem.class));
+        verify(row.getEntry().getSbn()).getLogMaker();  // This writes most of the log data
+        verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
+                MetricsProto.MetricsEvent.TYPE_ACTION));
+    }
+
+    @Test
+    public void testDismissListener() {
+        ArgumentCaptor<NotificationStackScrollLayout.DismissListener>
+                dismissListenerArgumentCaptor = ArgumentCaptor.forClass(
+                NotificationStackScrollLayout.DismissListener.class);
+
+        mController.attach(mNotificationStackScrollLayout);
+
+        verify(mNotificationStackScrollLayout).setDismissListener(
+                dismissListenerArgumentCaptor.capture());
+        NotificationStackScrollLayout.DismissListener dismissListener =
+                dismissListenerArgumentCaptor.getValue();
+
+        dismissListener.onDismiss(ROWS_ALL);
+        verify(mUiEventLogger).log(NotificationPanelEvent.fromSelection(ROWS_ALL));
+    }
+
+    @Test
+    public void testForegroundDismissEnabled() {
+        when(mFgFeatureController.isForegroundServiceDismissalEnabled()).thenReturn(true);
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mNotificationStackScrollLayout).initializeForegroundServiceSection(
+                mForegroundServiceDungeonView);
+    }
+
+    @Test
+    public void testForegroundDismissaDisabled() {
+        when(mFgFeatureController.isForegroundServiceDismissalEnabled()).thenReturn(false);
+        mController.attach(mNotificationStackScrollLayout);
+        verify(mNotificationStackScrollLayout, never()).initializeForegroundServiceSection(
+                any(ForegroundServiceDungeonView.class));
+    }
+
+    private LogMaker logMatcher(int category, int type) {
+        return argThat(new LogMatcher(category, type));
+    }
+
+    private void setupShowEmptyShadeViewState(
+            StatusBarStateController.StateListener statusBarStateListener,
+            boolean toShow) {
+        if (toShow) {
+            statusBarStateListener.onStateChanged(SHADE);
+            mController.setQsExpanded(false);
+            mController.getView().removeAllViews();
+        } else {
+            statusBarStateListener.onStateChanged(KEYGUARD);
+            mController.setQsExpanded(true);
+            mController.getView().addContainerView(mock(ExpandableNotificationRow.class));
+        }
+    }
+
+    static class LogMatcher implements ArgumentMatcher<LogMaker> {
+        private int mCategory, mType;
+
+        LogMatcher(int category, int type) {
+            mCategory = category;
+            mType = type;
+        }
+        public boolean matches(LogMaker l) {
+            return (l.getCategory() == mCategory)
+                    && (l.getType() == mType);
+        }
+
+        public String toString() {
+            return String.format("LogMaker(%d, %d)", mCategory, mType);
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
deleted file mode 100644
index f376e88..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ /dev/null
@@ -1,413 +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.statusbar.notification.stack;
-
-import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.StatusBarState.SHADE;
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-import android.metrics.LogMaker;
-import android.testing.AndroidTestingRunner;
-import android.view.LayoutInflater;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingCollectorFake;
-import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.media.KeyguardMediaController;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.tuner.TunerService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link NotificationStackScrollLayoutController}.
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class NotificationStackScrollerControllerTest extends SysuiTestCase {
-
-    @Mock private NotificationGutsManager mNotificationGutsManager;
-    @Mock private HeadsUpManagerPhone mHeadsUpManager;
-    @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
-    @Mock private TunerService mTunerService;
-    @Mock private DynamicPrivacyController mDynamicPrivacyController;
-    @Mock private ConfigurationController mConfigurationController;
-    @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
-    @Mock private ZenModeController mZenModeController;
-    @Mock private KeyguardMediaController mKeyguardMediaController;
-    @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
-    @Mock private KeyguardBypassController mKeyguardBypassController;
-    @Mock private SysuiColorExtractor mColorExtractor;
-    @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
-    @Mock private MetricsLogger mMetricsLogger;
-    @Mock private Resources mResources;
-    @Mock(answer = Answers.RETURNS_SELF)
-    private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
-    @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
-    @Mock private StatusBar mStatusBar;
-    @Mock private ScrimController mScrimController;
-    @Mock private NotificationGroupManagerLegacy mLegacyGroupManager;
-    @Mock private SectionHeaderController mSilentHeaderController;
-    @Mock private FeatureFlags mFeatureFlags;
-    @Mock private NotifPipeline mNotifPipeline;
-    @Mock private NotifCollection mNotifCollection;
-    @Mock private NotificationEntryManager mEntryManager;
-    @Mock private IStatusBarService mIStatusBarService;
-    @Mock private UiEventLogger mUiEventLogger;
-    @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    @Mock private ForegroundServiceDismissalFeatureController mFgFeatureController;
-    @Mock private ForegroundServiceSectionController mFgServicesSectionController;
-    @Mock private ForegroundServiceDungeonView mForegroundServiceDungeonView;
-    @Mock private LayoutInflater mLayoutInflater;
-    @Mock private NotificationRemoteInputManager mRemoteInputManager;
-    @Mock private RemoteInputController mRemoteInputController;
-    @Mock private VisualStabilityManager mVisualStabilityManager;
-    @Mock private ShadeController mShadeController;
-
-    @Captor
-    private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
-
-    private NotificationStackScrollLayoutController mController;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
-        when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
-        when(mFgServicesSectionController.createView(mLayoutInflater))
-                .thenReturn(mForegroundServiceDungeonView);
-        when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-
-        mController = new NotificationStackScrollLayoutController(
-                true,
-                mNotificationGutsManager,
-                mHeadsUpManager,
-                mNotificationRoundnessManager,
-                mTunerService,
-                mDynamicPrivacyController,
-                mConfigurationController,
-                mSysuiStatusBarStateController,
-                mKeyguardMediaController,
-                mKeyguardBypassController,
-                mZenModeController,
-                mColorExtractor,
-                mNotificationLockscreenUserManager,
-                mMetricsLogger,
-                new FalsingCollectorFake(),
-                new FalsingManagerFake(),
-                mResources,
-                mNotificationSwipeHelperBuilder,
-                mStatusBar,
-                mScrimController,
-                mLegacyGroupManager,
-                mLegacyGroupManager,
-                mSilentHeaderController,
-                mFeatureFlags,
-                mNotifPipeline,
-                mNotifCollection,
-                mEntryManager,
-                mLockscreenShadeTransitionController,
-                mIStatusBarService,
-                mUiEventLogger,
-                mFgFeatureController,
-                mFgServicesSectionController,
-                mLayoutInflater,
-                mRemoteInputManager,
-                mVisualStabilityManager,
-                mShadeController
-        );
-
-        when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
-    }
-
-    @Test
-    public void testAttach_viewAlreadyAttached() {
-        mController.attach(mNotificationStackScrollLayout);
-
-        verify(mConfigurationController).addCallback(
-                any(ConfigurationController.ConfigurationListener.class));
-    }
-    @Test
-    public void testAttach_viewAttachedAfterInit() {
-        when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(false);
-
-        mController.attach(mNotificationStackScrollLayout);
-
-        verify(mConfigurationController, never()).addCallback(
-                any(ConfigurationController.ConfigurationListener.class));
-
-        mController.mOnAttachStateChangeListener.onViewAttachedToWindow(
-                mNotificationStackScrollLayout);
-
-        verify(mConfigurationController).addCallback(
-                any(ConfigurationController.ConfigurationListener.class));
-    }
-
-    @Test
-    public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
-        mController.attach(mNotificationStackScrollLayout);
-        mController.mConfigurationListener.onDensityOrFontScaleChanged();
-        verify(mNotificationStackScrollLayout).reinflateViews();
-    }
-
-    @Test
-    public void testUpdateEmptyShadeView_notificationsVisible_zenHiding() {
-        when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mSysuiStatusBarStateController).addCallback(
-                mStateListenerArgumentCaptor.capture(), anyInt());
-        StatusBarStateController.StateListener stateListener =
-                mStateListenerArgumentCaptor.getValue();
-
-        setupShowEmptyShadeViewState(stateListener, true);
-        reset(mNotificationStackScrollLayout);
-        mController.updateShowEmptyShadeView();
-        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
-                true /* visible */,
-
-                true /* notifVisibleInShade */);
-
-        setupShowEmptyShadeViewState(stateListener, false);
-        reset(mNotificationStackScrollLayout);
-        mController.updateShowEmptyShadeView();
-        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
-                false /* visible */,
-                true /* notifVisibleInShade */);
-    }
-
-    @Test
-    public void testUpdateEmptyShadeView_notificationsHidden_zenNotHiding() {
-        when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mSysuiStatusBarStateController).addCallback(
-                mStateListenerArgumentCaptor.capture(), anyInt());
-        StatusBarStateController.StateListener stateListener =
-                mStateListenerArgumentCaptor.getValue();
-
-        setupShowEmptyShadeViewState(stateListener, true);
-        reset(mNotificationStackScrollLayout);
-        mController.updateShowEmptyShadeView();
-        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
-                true /* visible */,
-                false /* notifVisibleInShade */);
-
-        setupShowEmptyShadeViewState(stateListener, false);
-        reset(mNotificationStackScrollLayout);
-        mController.updateShowEmptyShadeView();
-        verify(mNotificationStackScrollLayout).updateEmptyShadeView(
-                false /* visible */,
-                false /* notifVisibleInShade */);
-    }
-
-    @Test
-    public void testOnUserChange_verifySensitiveProfile() {
-        when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
-
-        ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor
-                .forClass(UserChangedListener.class);
-
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mNotificationLockscreenUserManager)
-                .addUserChangedListener(userChangedCaptor.capture());
-        reset(mNotificationStackScrollLayout);
-
-        UserChangedListener changedListener = userChangedCaptor.getValue();
-        changedListener.onUserChanged(0);
-        verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
-    }
-
-    @Test
-    public void testOnStatePostChange_verifyIfProfileIsPublic() {
-        when(mNotificationLockscreenUserManager.isAnyProfilePublicMode()).thenReturn(true);
-
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mSysuiStatusBarStateController).addCallback(
-                mStateListenerArgumentCaptor.capture(), anyInt());
-
-        StatusBarStateController.StateListener stateListener =
-                mStateListenerArgumentCaptor.getValue();
-
-        stateListener.onStatePostChange();
-        verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
-    }
-
-    @Test
-    public void testOnMenuShownLogging() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
-        when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
-                MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
-        ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
-                ArgumentCaptor.forClass(OnMenuEventListener.class);
-
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
-                onMenuEventListenerArgumentCaptor.capture());
-
-        OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
-
-        onMenuEventListener.onMenuShown(row);
-        verify(row.getEntry().getSbn()).getLogMaker();  // This writes most of the log data
-        verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
-                MetricsProto.MetricsEvent.TYPE_ACTION));
-    }
-
-    @Test
-    public void testOnMenuClickedLogging() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
-        when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
-                MetricsProto.MetricsEvent.VIEW_UNKNOWN));
-
-        ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor =
-                ArgumentCaptor.forClass(OnMenuEventListener.class);
-
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mNotificationSwipeHelperBuilder).setOnMenuEventListener(
-                onMenuEventListenerArgumentCaptor.capture());
-
-        OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue();
-
-        onMenuEventListener.onMenuClicked(row, 0, 0, mock(
-                NotificationMenuRowPlugin.MenuItem.class));
-        verify(row.getEntry().getSbn()).getLogMaker();  // This writes most of the log data
-        verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
-                MetricsProto.MetricsEvent.TYPE_ACTION));
-    }
-
-    @Test
-    public void testDismissListener() {
-        ArgumentCaptor<NotificationStackScrollLayout.DismissListener>
-                dismissListenerArgumentCaptor = ArgumentCaptor.forClass(
-                NotificationStackScrollLayout.DismissListener.class);
-
-        mController.attach(mNotificationStackScrollLayout);
-
-        verify(mNotificationStackScrollLayout).setDismissListener(
-                dismissListenerArgumentCaptor.capture());
-        NotificationStackScrollLayout.DismissListener dismissListener =
-                dismissListenerArgumentCaptor.getValue();
-
-        dismissListener.onDismiss(ROWS_ALL);
-        verify(mUiEventLogger).log(NotificationPanelEvent.fromSelection(ROWS_ALL));
-    }
-
-    @Test
-    public void testForegroundDismissEnabled() {
-        when(mFgFeatureController.isForegroundServiceDismissalEnabled()).thenReturn(true);
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mNotificationStackScrollLayout).initializeForegroundServiceSection(
-                mForegroundServiceDungeonView);
-    }
-
-    @Test
-    public void testForegroundDismissaDisabled() {
-        when(mFgFeatureController.isForegroundServiceDismissalEnabled()).thenReturn(false);
-        mController.attach(mNotificationStackScrollLayout);
-        verify(mNotificationStackScrollLayout, never()).initializeForegroundServiceSection(
-                any(ForegroundServiceDungeonView.class));
-    }
-
-    private LogMaker logMatcher(int category, int type) {
-        return argThat(new LogMatcher(category, type));
-    }
-
-    private void setupShowEmptyShadeViewState(
-            StatusBarStateController.StateListener statusBarStateListener,
-            boolean toShow) {
-        if (toShow) {
-            statusBarStateListener.onStateChanged(SHADE);
-            mController.setQsExpanded(false);
-            mController.getView().removeAllViews();
-        } else {
-            statusBarStateListener.onStateChanged(KEYGUARD);
-            mController.setQsExpanded(true);
-            mController.getView().addContainerView(mock(ExpandableNotificationRow.class));
-        }
-    }
-
-    static class LogMatcher implements ArgumentMatcher<LogMaker> {
-        private int mCategory, mType;
-
-        LogMatcher(int category, int type) {
-            mCategory = category;
-            mType = type;
-        }
-        public boolean matches(LogMaker l) {
-            return (l.getCategory() == mCategory)
-                    && (l.getType() == mType);
-        }
-
-        public String toString() {
-            return String.format("LogMaker(%d, %d)", mCategory, mType);
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 2693b94..b2a7884 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -18,6 +18,8 @@
 
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
+import static com.android.keyguard.KeyguardClockSwitch.LARGE;
+import static com.android.keyguard.KeyguardClockSwitch.SMALL;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
@@ -35,6 +37,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -735,6 +738,38 @@
         verify(mTapAgainViewController).show();
     }
 
+    @Test
+    public void testSwitchesToCorrectClockInSinglePaneShade() {
+        mStatusBarStateController.setState(KEYGUARD);
+
+        when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0);
+        triggerPositionClockAndNotifications();
+        verify(mKeyguardStatusViewController).displayClock(LARGE);
+
+        when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1);
+        mNotificationPanelViewController.closeQs();
+        verify(mKeyguardStatusViewController).displayClock(SMALL);
+    }
+
+    @Test
+    public void testSwitchesToCorrectClockInSplitShade() {
+        mStatusBarStateController.setState(KEYGUARD);
+        enableSplitShade();
+
+        when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0);
+        triggerPositionClockAndNotifications();
+        verify(mKeyguardStatusViewController).displayClock(LARGE);
+
+        when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1);
+        triggerPositionClockAndNotifications();
+        verify(mKeyguardStatusViewController, times(2)).displayClock(LARGE);
+        verify(mKeyguardStatusViewController, never()).displayClock(SMALL);
+    }
+
+    private void triggerPositionClockAndNotifications() {
+        mNotificationPanelViewController.closeQs();
+    }
+
     private FalsingManager.FalsingTapListener getFalsingTapListener() {
         for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
             listener.onViewAttachedToWindow(mView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 678b193..2685b76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -576,6 +576,49 @@
     }
 
     @Test
+    public void disableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() {
+        mScrimController.setClipsQsScrim(true);
+        mScrimController.transitionTo(ScrimState.BOUNCER);
+
+        mScrimController.setClipsQsScrim(false);
+
+        finishAnimationsImmediately();
+        // Front scrim should be transparent
+        // Back scrim should be visible without tint
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, TRANSPARENT,
+                mScrimBehind, OPAQUE));
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, false,
+                mNotificationsScrim, false
+        ));
+    }
+
+    @Test
+    public void enableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() {
+        mScrimController.setClipsQsScrim(false);
+        mScrimController.transitionTo(ScrimState.BOUNCER);
+
+        mScrimController.setClipsQsScrim(true);
+
+        finishAnimationsImmediately();
+        // Front scrim should be transparent
+        // Back scrim should be clipping QS
+        // Notif scrim should be visible without tint
+        assertScrimAlpha(Map.of(
+                mScrimInFront, TRANSPARENT,
+                mNotificationsScrim, OPAQUE,
+                mScrimBehind, OPAQUE));
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, true,
+                mNotificationsScrim, false
+        ));
+    }
+
+    @Test
     public void transitionToBouncer() {
         mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED);
         finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index dd8354d..0d4d889 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static android.view.ContentInfo.SOURCE_CLIPBOARD;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
 
@@ -25,15 +27,19 @@
 import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
+import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ShortcutManager;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.ContentInfo;
 import android.view.View;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -238,4 +244,39 @@
                 RemoteInputView.NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_SEND.getId(),
                 mUiEventLoggerFake.eventId(1));
     }
+
+    @Test
+    public void testUiEventLogging_openAndAttach() throws Exception {
+        NotificationTestHelper helper = new NotificationTestHelper(
+                mContext,
+                mDependency,
+                TestableLooper.get(this));
+        ExpandableNotificationRow row = helper.createRow();
+        RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
+
+        setTestPendingIntent(view);
+
+        // Open view, attach an image
+        view.focus();
+        EditText editText = view.findViewById(R.id.remote_input_text);
+        editText.setText(TEST_REPLY);
+        ClipDescription description = new ClipDescription("", new String[] {"image/png"});
+        // We need to use an (arbitrary) real resource here so that an actual image gets attached.
+        ClipData clip = new ClipData(description, new ClipData.Item(
+                Uri.parse("android.resource://com.android.systemui/"
+                        + R.drawable.default_thumbnail)));
+        ContentInfo payload =
+                new ContentInfo.Builder(clip, SOURCE_CLIPBOARD).build();
+        view.setAttachment(payload);
+        mReceiver.waitForIntent();
+
+        assertEquals(2, mUiEventLoggerFake.numLogs());
+        assertEquals(
+                RemoteInputView.NotificationRemoteInputEvent.NOTIFICATION_REMOTE_INPUT_OPEN.getId(),
+                mUiEventLoggerFake.eventId(0));
+        assertEquals(
+                RemoteInputView.NotificationRemoteInputEvent
+                        .NOTIFICATION_REMOTE_INPUT_ATTACH_IMAGE.getId(),
+                mUiEventLoggerFake.eventId(1));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
new file mode 100644
index 0000000..019bd8d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.app.IActivityTaskManager
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.graphics.Bitmap
+import android.hardware.face.FaceManager
+import android.hardware.fingerprint.FingerprintManager
+import android.os.Handler
+import android.os.UserHandle
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.util.UserIcons
+import com.android.systemui.GuestResumeSessionReceiver
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.QSUserSwitcherEvent
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.telephony.TelephonyListenerManager
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class UserSwitcherControllerTest : SysuiTestCase() {
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock private lateinit var handler: Handler
+    @Mock private lateinit var userTracker: UserTracker
+    @Mock private lateinit var userManager: UserManager
+    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock private lateinit var activityTaskManager: IActivityTaskManager
+    @Mock private lateinit var userDetailAdapter: UserSwitcherController.UserDetailAdapter
+    @Mock private lateinit var telephonyListenerManager: TelephonyListenerManager
+    @Mock private lateinit var secureSettings: SecureSettings
+    private lateinit var testableLooper: TestableLooper
+    private lateinit var uiBgExecutor: FakeExecutor
+    private lateinit var uiEventLogger: UiEventLoggerFake
+    private lateinit var userSwitcherController: UserSwitcherController
+    private lateinit var picture: Bitmap
+    private val ownerId = UserHandle.USER_SYSTEM
+    private val ownerInfo = UserInfo(ownerId, "Owner", null,
+            UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or
+                    UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM,
+            UserManager.USER_TYPE_FULL_SYSTEM)
+    private val guestId = 1234
+    private val guestInfo = UserInfo(guestId, "Guest", null,
+            UserInfo.FLAG_FULL or UserInfo.FLAG_GUEST, UserManager.USER_TYPE_FULL_GUEST)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
+        uiBgExecutor = FakeExecutor(FakeSystemClock())
+        uiEventLogger = UiEventLoggerFake()
+
+        context.orCreateTestableResources.addOverride(
+                com.android.internal.R.bool.config_guestUserAutoCreated, false)
+
+        mContext.addMockSystemService(Context.FACE_SERVICE, mock(FaceManager::class.java))
+        mContext.addMockSystemService(Context.FINGERPRINT_SERVICE,
+                mock(FingerprintManager::class.java))
+
+        `when`(userManager.canAddMoreUsers()).thenReturn(true)
+
+        userSwitcherController = UserSwitcherController(context,
+                userManager,
+                userTracker,
+                keyguardStateController,
+                handler,
+                activityStarter,
+                broadcastDispatcher,
+                uiEventLogger,
+                telephonyListenerManager,
+                activityTaskManager,
+                userDetailAdapter,
+                secureSettings,
+                uiBgExecutor)
+        userSwitcherController.mPauseRefreshUsers = true
+
+        picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user))
+    }
+
+    @Test
+    fun testAddGuest_okButtonPressed_isLogged() {
+        val emptyGuestUserRecord = UserSwitcherController.UserRecord(
+                null,
+                null,
+                true /* guest */,
+                false /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(ownerId)
+        `when`(userTracker.userInfo).thenReturn(ownerInfo)
+
+        `when`(userManager.createGuest(any(), anyString())).thenReturn(guestInfo)
+
+        userSwitcherController.onUserListItemClicked(emptyGuestUserRecord)
+        testableLooper.processAllMessages()
+        assertEquals(1, uiEventLogger.numLogs())
+        assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_ADD.id, uiEventLogger.eventId(0))
+    }
+
+    @Test
+    fun testRemoveGuest_removeButtonPressed_isLogged() {
+        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+                guestInfo,
+                picture,
+                true /* guest */,
+                true /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(guestInfo.id)
+        `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+        assertNotNull(userSwitcherController.mExitGuestDialog)
+        userSwitcherController.mExitGuestDialog
+                .getButton(DialogInterface.BUTTON_POSITIVE).performClick()
+        testableLooper.processAllMessages()
+        assertEquals(1, uiEventLogger.numLogs())
+        assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE.id, uiEventLogger.eventId(0))
+    }
+
+    @Test
+    fun testRemoveGuest_cancelButtonPressed_isNotLogged() {
+        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+                guestInfo,
+                picture,
+                true /* guest */,
+                true /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(guestId)
+        `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+        assertNotNull(userSwitcherController.mExitGuestDialog)
+        userSwitcherController.mExitGuestDialog
+                .getButton(DialogInterface.BUTTON_NEGATIVE).performClick()
+        testableLooper.processAllMessages()
+        assertEquals(0, uiEventLogger.numLogs())
+    }
+
+    @Test
+    fun testWipeGuest_startOverButtonPressed_isLogged() {
+        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+                guestInfo,
+                picture,
+                true /* guest */,
+                false /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(guestId)
+        `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+        // Simulate that guest user has already logged in
+        `when`(secureSettings.getIntForUser(
+                eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
+                .thenReturn(1)
+
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+
+        // Simulate a user switch event
+        val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
+
+        assertNotNull(userSwitcherController.mGuestResumeSessionReceiver)
+        userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)
+
+        assertNotNull(userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog)
+        userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog
+                .getButton(GuestResumeSessionReceiver.ResetSessionDialog.BUTTON_WIPE).performClick()
+        testableLooper.processAllMessages()
+        assertEquals(1, uiEventLogger.numLogs())
+        assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_WIPE.id, uiEventLogger.eventId(0))
+    }
+
+    @Test
+    fun testWipeGuest_continueButtonPressed_isLogged() {
+        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+                guestInfo,
+                picture,
+                true /* guest */,
+                false /* current */,
+                false /* isAddUser */,
+                false /* isRestricted */,
+                true /* isSwitchToEnabled */)
+        `when`(userTracker.userId).thenReturn(guestId)
+        `when`(userTracker.userInfo).thenReturn(guestInfo)
+
+        // Simulate that guest user has already logged in
+        `when`(secureSettings.getIntForUser(
+                eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
+                .thenReturn(1)
+
+        userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
+
+        // Simulate a user switch event
+        val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
+
+        assertNotNull(userSwitcherController.mGuestResumeSessionReceiver)
+        userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)
+
+        assertNotNull(userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog)
+        userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog
+                .getButton(GuestResumeSessionReceiver.ResetSessionDialog.BUTTON_DONTWIPE)
+                .performClick()
+        testableLooper.processAllMessages()
+        assertEquals(1, uiEventLogger.numLogs())
+        assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_CONTINUE.id, uiEventLogger.eventId(0))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index eb9206d..56cbf29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -120,6 +120,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import com.google.common.collect.ImmutableList;
@@ -329,7 +330,8 @@
                 mPositioner,
                 mock(DisplayController.class),
                 syncExecutor,
-                mock(Handler.class));
+                mock(Handler.class),
+                mock(SyncTransactionQueue.class));
         mBubbleController.setExpandListener(mBubbleExpandListener);
         spyOn(mBubbleController);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 24a5b3a..9c16e5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -99,6 +99,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.Before;
@@ -272,7 +273,8 @@
                 mPositioner,
                 mock(DisplayController.class),
                 syncExecutor,
-                mock(Handler.class));
+                mock(Handler.class),
+                mock(SyncTransactionQueue.class));
         mBubbleController.setExpandListener(mBubbleExpandListener);
         spyOn(mBubbleController);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index cd5aa9a..7b77cb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -32,6 +32,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 
 /**
@@ -54,11 +55,12 @@
             BubblePositioner positioner,
             DisplayController displayController,
             ShellExecutor shellMainExecutor,
-            Handler shellMainHandler) {
+            Handler shellMainHandler,
+            SyncTransactionQueue syncQueue) {
         super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
                 statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
                 bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
-                shellMainExecutor, shellMainHandler);
+                shellMainExecutor, shellMainHandler, syncQueue);
         setInflateSynchronously(true);
         initialize();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 5691660..8480702 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -41,6 +41,7 @@
 import com.android.wm.shell.onehanded.OneHandedEventCallback;
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
 import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.splitscreen.SplitScreen;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,6 +70,7 @@
     @Mock SysUiState mSysUiState;
     @Mock Pip mPip;
     @Mock LegacySplitScreen mLegacySplitScreen;
+    @Mock SplitScreen mSplitScreen;
     @Mock OneHanded mOneHanded;
     @Mock HideDisplayCutout mHideDisplayCutout;
     @Mock WakefulnessLifecycle mWakefulnessLifecycle;
@@ -81,7 +83,7 @@
         MockitoAnnotations.initMocks(this);
 
         mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
-                Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
+                Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
                 Optional.of(mShellCommandHandler), mCommandQueue, mConfigurationController,
                 mKeyguardUpdateMonitor, mNavigationModeController,
                 mScreenLifecycle, mSysUiState, mProtoTracer, mWakefulnessLifecycle,
@@ -96,8 +98,15 @@
     }
 
     @Test
+    public void initLegacySplitScreen_registersCallbacks() {
+        mWMShell.initLegacySplitScreen(mLegacySplitScreen);
+
+        verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
+    }
+
+    @Test
     public void initSplitScreen_registersCallbacks() {
-        mWMShell.initSplitScreen(mLegacySplitScreen);
+        mWMShell.initSplitScreen(mSplitScreen);
 
         verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
     }
diff --git a/packages/VpnDialogs/res/values-af/strings.xml b/packages/VpnDialogs/res/values-af/strings.xml
index ac82b0e..88ccbd9 100644
--- a/packages/VpnDialogs/res/values-af/strings.xml
+++ b/packages/VpnDialogs/res/values-af/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Verbindingversoek"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wil \'n VPN-verbinding opstel wat dit sal toelaat om netwerkverkeer te monitor. Aanvaar dit net as jy die bron vertrou. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; verskyn boaan jou skerm as VPN aktief is."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wil \'n VPN-verbinding opstel wat dit toelaat om netwerkverkeer te monitor. Aanvaar dit net as jy die bron vertrou. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; verskyn op jou skerm wanneer VPN aktief is."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN is gekoppel"</string>
     <string name="session" msgid="6470628549473641030">"Sessie:"</string>
     <string name="duration" msgid="3584782459928719435">"Tydsduur:"</string>
diff --git a/packages/VpnDialogs/res/values-am/strings.xml b/packages/VpnDialogs/res/values-am/strings.xml
index ad9773b..9fc5ff4 100644
--- a/packages/VpnDialogs/res/values-am/strings.xml
+++ b/packages/VpnDialogs/res/values-am/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"የግንኙነት ጥያቄ"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> የአውታረ መረብ መከታተል የሚያስችል የVPN ግንኑነት ማዋቀር ይፈልጋል። ምንጩን የሚያምኑት ብቻ ከሆኑ ይቀበሉ። &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN ገቢር ሲሆን በማያ ገጽዎ ላይኛው ክፍል ላይ ይታያል።"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> የአውታረ መረብ ትራፊክን ለመቆጣጠር የሚያስችል የVPN ግንኙነትን ማዋቀር ይፈልጋል። ምንጩን የሚያምኑ ከሆነ ብቻ ይቀበሉ። &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ማያ ገጹ ላይ VPN ገቢር ሲሆን ይታያል።"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ተያይዟል"</string>
     <string name="session" msgid="6470628549473641030">"ክፍለ ጊዜ፡"</string>
     <string name="duration" msgid="3584782459928719435">"ጊዜ"</string>
diff --git a/packages/VpnDialogs/res/values-ar/strings.xml b/packages/VpnDialogs/res/values-ar/strings.xml
index 808cde9..33be6a3 100644
--- a/packages/VpnDialogs/res/values-ar/strings.xml
+++ b/packages/VpnDialogs/res/values-ar/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"طلب الاتصال"</string>
     <string name="warning" msgid="809658604548412033">"‏يريد <xliff:g id="APP">%s</xliff:g> إعداد الاتصال بالشبكة الافتراضية الخاصة التي تتيح له مراقبة حركة المرور على الشبكة. فلا توافق إلا إذا كنت تثق في المصدر. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; يظهر في الجزء العلوي من الشاشة عندما تكون الشبكة الافتراضية الخاصة نشطة."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"‏يريد تطبيق <xliff:g id="APP">%s</xliff:g> إعداد اتصال شبكة افتراضية خاصة (VPN) يتيح له مراقبة حركة بيانات الشبكة. لا تقبل السماح بذلك إلا إذا كنت تثق في المصدر. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; يظهر على شاشتك عندما تكون الشبكة الافتراضية الخاصة نشطة."</string>
     <string name="legacy_title" msgid="192936250066580964">"‏VPN متصلة"</string>
     <string name="session" msgid="6470628549473641030">"الجلسة"</string>
     <string name="duration" msgid="3584782459928719435">"المدة:"</string>
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index 45d8458..4669a69 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"সংযোগৰ অনুৰোধ"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>এ নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ এটা ভিপিএন সংযোগ ছেট আপ কৰিবলৈ বিচাৰিছে৷ আপুনি কেৱল উৎসটোক বিশ্বাস কৰিলেহে অনুৰোধ স্বীকাৰ কৰিব৷ ভিপিএন সক্ৰিয় থকাৰ সময়ত আপোনাৰ স্ক্ৰীণৰ ওপৰত &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; দৃশ্যমান হয়৷"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>এ এটা ভিপিএন সংযোগ ছেট আপ কৰিব বিচাৰে, যিটোৱে ইয়াক নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ দিয়ে। আপুনি উৎসটোক বিশ্বাস কৰিলেহে গ্ৰহণ কৰক। ভিপিএনটো সক্ৰিয় হৈ থকাৰ সময়ত আপোনাৰ স্ক্ৰীনত&lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; প্ৰদৰ্শিত হয়।"</string>
     <string name="legacy_title" msgid="192936250066580964">"ভিপিএন সংযোগ হৈ আছে"</string>
     <string name="session" msgid="6470628549473641030">"ছেশ্বন:"</string>
     <string name="duration" msgid="3584782459928719435">"সময়সীমা:"</string>
diff --git a/packages/VpnDialogs/res/values-az/strings.xml b/packages/VpnDialogs/res/values-az/strings.xml
index 2bdf23e..d878835 100644
--- a/packages/VpnDialogs/res/values-az/strings.xml
+++ b/packages/VpnDialogs/res/values-az/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Bağlantı Sorğusu"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> VPN bağlantı yaratmaq istəyir ki, bu da şəbəkə trafikini izləyə bilər. Yalnız mənbəyə güvəndiyiniz halda qəbul edin. VPN aktiv olan zaman &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ekranın yuxarısında görünür."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> şəbəkə trafikini izləməyə imkan verən VPN bağlantısı yaratmaq istəyir. Yalnız mənbəyə güvəndiyiniz halda qəbul edin. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN aktiv olan zaman ekranda görünür."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN qoşuludur"</string>
     <string name="session" msgid="6470628549473641030">"Sessiya:"</string>
     <string name="duration" msgid="3584782459928719435">"Müddət:"</string>
diff --git a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
index f40e406..a1075d2 100644
--- a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
+++ b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Zahtev za povezivanje"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> želi da podesi VPN vezu koja omogućava praćenje saobraćaja na mreži. Prihvatite samo ako verujete izvoru. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se prikazuje u vrhu ekrana kada je VPN aktivan."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi da podesi VPN vezu koja joj omogućava da prati mrežni saobraćaj. Prihvatite ovo samo ako imate poverenja u izvor. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se prikazuje na ekranu kada je VPN aktivan."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN je povezan"</string>
     <string name="session" msgid="6470628549473641030">"Sesija:"</string>
     <string name="duration" msgid="3584782459928719435">"Trajanje:"</string>
diff --git a/packages/VpnDialogs/res/values-be/strings.xml b/packages/VpnDialogs/res/values-be/strings.xml
index 0903c8e..fc3f878 100644
--- a/packages/VpnDialogs/res/values-be/strings.xml
+++ b/packages/VpnDialogs/res/values-be/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Запыт на падлучэнне"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> спрабуе наладзіць падлучэнне VPN, якое дазваляе сачыць за сеткавым трафікам. Прымайце толькі тады, калі вы давяраеце гэтай крыніцы. Калі VPN актыўны, у верхняй частцы экрана адлюстроўваецца &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Праграма \"<xliff:g id="APP">%s</xliff:g>\" запытвае дазвол на падключэнне да сеткі VPN, каб адсочваць сеткавы трафік. Дайце дазвол, толькі калі вы давяраеце крыніцы. Калі адбудзецца падключэнне да VPN, на экране з\'явіцца значок &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN падключаны"</string>
     <string name="session" msgid="6470628549473641030">"Сессія"</string>
     <string name="duration" msgid="3584782459928719435">"Працягласць:"</string>
diff --git a/packages/VpnDialogs/res/values-bg/strings.xml b/packages/VpnDialogs/res/values-bg/strings.xml
index 9ac853d..6345f1d 100644
--- a/packages/VpnDialogs/res/values-bg/strings.xml
+++ b/packages/VpnDialogs/res/values-bg/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Заявка за свързване"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> иска да настрои връзка с виртуална частна мрежа (VPN), за да може да наблюдава мрежовия трафик. Приемете само ако източникът е надежден. Иконата &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; се показва в долната част на екрана при активирана VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> иска да настрои връзка с VPN, за да може да наблюдава трафика в мрежата. Приемете само ако източникът е надежден. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; се показва на екрана при активирана VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN е свързана"</string>
     <string name="session" msgid="6470628549473641030">"Сесия:"</string>
     <string name="duration" msgid="3584782459928719435">"Продължителност:"</string>
diff --git a/packages/VpnDialogs/res/values-bn/strings.xml b/packages/VpnDialogs/res/values-bn/strings.xml
index 5e11fd9..352b786 100644
--- a/packages/VpnDialogs/res/values-bn/strings.xml
+++ b/packages/VpnDialogs/res/values-bn/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"সংযোগের অনুরোধ"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> এমন একটি VPN সংযোগ সেট-আপ করতে চাচ্ছে যেটি দিয়ে এটি নেটওয়ার্ক ট্রাফিক নিরীক্ষণ করতে পারবে। আপনি যদি উৎসটিকে বিশ্বাস করেন, তাহলেই কেবল এতে সম্মতি দিন। VPN সক্রিয় থাকলে আপনার স্ক্রীনের উপরে &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; দেখা যাবে।"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> এমন একটি VPN সংযোগ সেট আপ করতে চাইছে যেটি দিয়ে এটি নেটওয়ার্ক ট্রাফিক নিরীক্ষণ করতে পারবে। আপনি সোর্সটি বিশ্বাস করলে একমাত্র তখনই অ্যাক্সেপ্ট করুন। PN অ্যাক্টিভ থাকলে &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; আপনার স্ক্রিনে দেখা যায়।"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN সংযুক্ত হয়েছে"</string>
     <string name="session" msgid="6470628549473641030">"অধিবেশন:"</string>
     <string name="duration" msgid="3584782459928719435">"সময়কাল:"</string>
diff --git a/packages/VpnDialogs/res/values-bs/strings.xml b/packages/VpnDialogs/res/values-bs/strings.xml
index 56812d5..fa5f4ea 100644
--- a/packages/VpnDialogs/res/values-bs/strings.xml
+++ b/packages/VpnDialogs/res/values-bs/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Zahtjev za povezivanje"</string>
     <string name="warning" msgid="809658604548412033">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi podesiti VPN vezu koja joj omogućava praćenje mrežnog saobraćaja. Prihvatite samo ako je izvor pouzdan. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se pojavi na vrhu ekrana kada je VPN aktivna."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi postaviti VPN vezu koja joj omogućava praćenje mrežnog saobraćaja. Prihvatite samo ako vjerujete izvoru. Kada je VPN aktivan, na ekranu se prikazuje ikona &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN veza uspostavljena"</string>
     <string name="session" msgid="6470628549473641030">"Sesija:"</string>
     <string name="duration" msgid="3584782459928719435">"Trajanje:"</string>
diff --git a/packages/VpnDialogs/res/values-ca/strings.xml b/packages/VpnDialogs/res/values-ca/strings.xml
index 97738c3..cdb7547 100644
--- a/packages/VpnDialogs/res/values-ca/strings.xml
+++ b/packages/VpnDialogs/res/values-ca/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Sol·licitud de connexió"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vol configurar una connexió VPN que li permeti controlar el trànsit de xarxa. Accepta la sol·licitud només si prové d\'una font de confiança. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; es mostra a la part superior de la pantalla quan la VPN està activada."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> vol configurar una connexió VPN que li permeti monitorar el trànsit de xarxa. Accepta la sol·licitud només si prové d\'una font de confiança. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; és la icona que veuràs a la pantalla quan la VPN estigui activa."</string>
     <string name="legacy_title" msgid="192936250066580964">"La VPN està connectada"</string>
     <string name="session" msgid="6470628549473641030">"Sessió:"</string>
     <string name="duration" msgid="3584782459928719435">"Durada:"</string>
diff --git a/packages/VpnDialogs/res/values-cs/strings.xml b/packages/VpnDialogs/res/values-cs/strings.xml
index 5cc809c..c06f6ff 100644
--- a/packages/VpnDialogs/res/values-cs/strings.xml
+++ b/packages/VpnDialogs/res/values-cs/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Žádost o připojení"</string>
     <string name="warning" msgid="809658604548412033">"Aplikace <xliff:g id="APP">%s</xliff:g> žádá o nastavení připojení VPN, pomocí kterého bude moci sledovat síťový provoz. Povolte, jen pokud zdroji důvěřujete. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; – když je síť VPN aktivní, v horní části obrazovky se zobrazuje tato ikona."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikace <xliff:g id="APP">%s</xliff:g> chce nastavit připojení VPN, které umožňuje sledovat síťový provoz. Povolte, jen pokud zdroji důvěřujete. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; – když je síť VPN aktivní, na obrazovce se zobrazuje tato ikona."</string>
     <string name="legacy_title" msgid="192936250066580964">"Síť VPN je připojena"</string>
     <string name="session" msgid="6470628549473641030">"Relace:"</string>
     <string name="duration" msgid="3584782459928719435">"Doba trvání:"</string>
diff --git a/packages/VpnDialogs/res/values-da/strings.xml b/packages/VpnDialogs/res/values-da/strings.xml
index 7641158..a4ddc19 100644
--- a/packages/VpnDialogs/res/values-da/strings.xml
+++ b/packages/VpnDialogs/res/values-da/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Forbindelsesanmodning"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vil konfigurere en VPN-forbindelse, der giver appen mulighed for at registrere netværkstrafik. Du bør kun acceptere dette, hvis du har tillid til kilden. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; vises øverst på din skærm, når VPN-forbindelsen er aktiv."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> anmoder om at konfigurere en VPN-forbindelse, der giver appen tilladelse til at holde øje med netværkstrafik. Du bør kun acceptere dette, hvis du har tillid til appen. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; vises på din skærm, når VPN-forbindelsen er aktiv."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN er tilsluttet"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Varighed:"</string>
diff --git a/packages/VpnDialogs/res/values-de/strings.xml b/packages/VpnDialogs/res/values-de/strings.xml
index 0f1e009..f38e395 100644
--- a/packages/VpnDialogs/res/values-de/strings.xml
+++ b/packages/VpnDialogs/res/values-de/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Verbindungsanfrage"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lass die Verbindung nur zu, wenn die App vertrauenswürdig ist. Wenn VPN aktiv ist, wird oben im Display &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; angezeigt."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lass die Verbindung nur zu, wenn die App vertrauenswürdig ist. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; wird auf dem Display angezeigt, wenn VPN aktiv ist."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ist verbunden"</string>
     <string name="session" msgid="6470628549473641030">"Sitzung:"</string>
     <string name="duration" msgid="3584782459928719435">"Dauer:"</string>
diff --git a/packages/VpnDialogs/res/values-el/strings.xml b/packages/VpnDialogs/res/values-el/strings.xml
index 78bcc43..e3eb460 100644
--- a/packages/VpnDialogs/res/values-el/strings.xml
+++ b/packages/VpnDialogs/res/values-el/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Αίτημα σύνδεσης"</string>
     <string name="warning" msgid="809658604548412033">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> επιθυμεί να ρυθμίσει μια σύνδεση VPN που της επιτρέπει να παρακολουθεί την επισκεψιμότητα του δικτύου. Αποδεχτείτε το αίτημα μόνο εάν εμπιστεύεστε την πηγή. Το εικονίδιο &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; εμφανίζεται στο επάνω μέρος της οθόνης σας όταν είναι ενεργό το VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> επιθυμεί να ρυθμίσει μια σύνδεση VPN που της επιτρέπει να παρακολουθεί την επισκεψιμότητα του δικτύου. Αποδεχτείτε το αίτημα μόνο εάν εμπιστεύεστε την πηγή. Το εικονίδιο &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; εμφανίζεται στην οθόνη σας όταν είναι ενεργό το VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"Το VPN συνδέθηκε"</string>
     <string name="session" msgid="6470628549473641030">"Περίοδος σύνδεσης"</string>
     <string name="duration" msgid="3584782459928719435">"Διάρκεια:"</string>
diff --git a/packages/VpnDialogs/res/values-en-rAU/strings.xml b/packages/VpnDialogs/res/values-en-rAU/strings.xml
index 6ed50a7..cb8b79d 100644
--- a/packages/VpnDialogs/res/values-en-rAU/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rAU/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Connection request"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears at the top of your screen when VPN is active."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears on your screen when VPN is active."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN is connected"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Duration:"</string>
diff --git a/packages/VpnDialogs/res/values-en-rCA/strings.xml b/packages/VpnDialogs/res/values-en-rCA/strings.xml
index 6ed50a7..cb8b79d 100644
--- a/packages/VpnDialogs/res/values-en-rCA/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rCA/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Connection request"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears at the top of your screen when VPN is active."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears on your screen when VPN is active."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN is connected"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Duration:"</string>
diff --git a/packages/VpnDialogs/res/values-en-rGB/strings.xml b/packages/VpnDialogs/res/values-en-rGB/strings.xml
index 6ed50a7..cb8b79d 100644
--- a/packages/VpnDialogs/res/values-en-rGB/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rGB/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Connection request"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears at the top of your screen when VPN is active."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears on your screen when VPN is active."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN is connected"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Duration:"</string>
diff --git a/packages/VpnDialogs/res/values-en-rIN/strings.xml b/packages/VpnDialogs/res/values-en-rIN/strings.xml
index 6ed50a7..cb8b79d 100644
--- a/packages/VpnDialogs/res/values-en-rIN/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rIN/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Connection request"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears at the top of your screen when VPN is active."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears on your screen when VPN is active."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN is connected"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Duration:"</string>
diff --git a/packages/VpnDialogs/res/values-en-rXC/strings.xml b/packages/VpnDialogs/res/values-en-rXC/strings.xml
index 9d010e6..f5e2deb 100644
--- a/packages/VpnDialogs/res/values-en-rXC/strings.xml
+++ b/packages/VpnDialogs/res/values-en-rXC/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎Connection request‎‏‎‎‏‎"</string>
     <string name="warning" msgid="809658604548412033">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎ wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears at the top of your screen when VPN is active.‎‏‎‎‏‎"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎ wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; appears on your screen when VPN is active.‎‏‎‎‏‎"</string>
     <string name="legacy_title" msgid="192936250066580964">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎VPN is connected‎‏‎‎‏‎"</string>
     <string name="session" msgid="6470628549473641030">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎Session:‎‏‎‎‏‎"</string>
     <string name="duration" msgid="3584782459928719435">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎Duration:‎‏‎‎‏‎"</string>
diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml
index 21cfc04..108a24e 100644
--- a/packages/VpnDialogs/res/values-es-rUS/strings.xml
+++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN capaz de controlar el tráfico de la red. Acéptala solo si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece en la parte superior de la pantalla cuando se activa la VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que le permita supervisar el tráfico de red. Solo acéptala si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparecerá en tu pantalla cuando se active la VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"La VPN está conectada."</string>
     <string name="session" msgid="6470628549473641030">"Sesión:"</string>
     <string name="duration" msgid="3584782459928719435">"Duración:"</string>
diff --git a/packages/VpnDialogs/res/values-es/strings.xml b/packages/VpnDialogs/res/values-es/strings.xml
index 372147f..0eaf359 100644
--- a/packages/VpnDialogs/res/values-es/strings.xml
+++ b/packages/VpnDialogs/res/values-es/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN para controlar el tráfico de red. Solo debes aceptarla si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece en la parte superior de la pantalla cuando se active la conexión VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que le permita monitorizar el tráfico de red. Acéptalo solo si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparecerá en la pantalla cuando la VPN esté activa."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN conectada"</string>
     <string name="session" msgid="6470628549473641030">"Sesión:"</string>
     <string name="duration" msgid="3584782459928719435">"Duración:"</string>
diff --git a/packages/VpnDialogs/res/values-et/strings.xml b/packages/VpnDialogs/res/values-et/strings.xml
index c328cd7..140c183 100644
--- a/packages/VpnDialogs/res/values-et/strings.xml
+++ b/packages/VpnDialogs/res/values-et/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Ühendamise taotlus"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> tahab seadistada VPN-i ühenduse, mis võimaldab jälgida võrguliiklust. Nõustuge ainult siis, kui usaldate seda allikat. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; kuvatakse ekraani ülaservas, kui VPN on aktiivne."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> tahab seadistada VPN-i ühenduse, mis võimaldab jälgida võrguliiklust. Nõustuge ainult siis, kui usaldate seda allikat. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; kuvatakse ekraanil, kui VPN on aktiivne."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN on ühendatud"</string>
     <string name="session" msgid="6470628549473641030">"Seansid"</string>
     <string name="duration" msgid="3584782459928719435">"Kestus:"</string>
diff --git a/packages/VpnDialogs/res/values-eu/strings.xml b/packages/VpnDialogs/res/values-eu/strings.xml
index a3b7716e..9fc16e2 100644
--- a/packages/VpnDialogs/res/values-eu/strings.xml
+++ b/packages/VpnDialogs/res/values-eu/strings.xml
@@ -18,13 +18,14 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Konektatzeko eskaera"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN bidezko konexioa ezarri nahi du sareko trafikoa kontrolatzeko. Iturburua fidagarria bada bakarrik baimendu. &lt;br /&gt; &lt;br /&gt; VPN konexioa aktibo dagoenean, &lt;img src=vpn_icon /&gt; agertuko da pantailaren goialdean."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN bidezko konexio bat konfiguratu nahi du sareko trafikoa gainbegiratzeko. Onartu soilik iturburuaz fidatzen bazara. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; agertzen da pantailan, VPNa aktibo dagoenean."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN sarera konektatuta dago"</string>
     <string name="session" msgid="6470628549473641030">"Saioa:"</string>
     <string name="duration" msgid="3584782459928719435">"Iraupena:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"Bidalita:"</string>
     <string name="data_received" msgid="4062776929376067820">"Jasota:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> byte / <xliff:g id="NUMBER_1">%2$s</xliff:g> pakete"</string>
-    <string name="always_on_disconnected_title" msgid="1906740176262776166">"Ezin da konektatu beti aktibatuta dagoen VPN sarea"</string>
+    <string name="always_on_disconnected_title" msgid="1906740176262776166">"Ezin da konektatu beti aktibatuta dagoen VPNa"</string>
     <string name="always_on_disconnected_message" msgid="555634519845992917">"Beti aktibatuta egoteko dago konfiguratuta <xliff:g id="VPN_APP_0">%1$s</xliff:g>, baina une honetan ezin da konektatu. <xliff:g id="VPN_APP_1">%1$s</xliff:g> sarera berriro konektatu ahal izan arte, sare publiko bat erabiliko du telefonoak."</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"Beti aktibatuta egoteko dago konfiguratuta <xliff:g id="VPN_APP">%1$s</xliff:g>, baina une honetan ezin da konektatu. VPN sarearen konexioa berreskuratu arte, ez duzu izango konexiorik."</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
diff --git a/packages/VpnDialogs/res/values-fa/strings.xml b/packages/VpnDialogs/res/values-fa/strings.xml
index 56f847c..6fb5a00 100644
--- a/packages/VpnDialogs/res/values-fa/strings.xml
+++ b/packages/VpnDialogs/res/values-fa/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"درخواست اتصال"</string>
     <string name="warning" msgid="809658604548412033">"‏<xliff:g id="APP">%s</xliff:g> می‌خواهد یک اتصال VPN راه‌اندازی کند که به آن امکان نظارت بر ترافیک شبکه را می‌دهد. فقط در صورتی بپذیرید که به منبع آن اطمینان دارید. هنگامی که VPN فعال شد، &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; در بالای صفحه نمایش شما نشان داده می‌شود."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"‏<xliff:g id="APP">%s</xliff:g> می‌خواهد یک اتصال VPN راه‌اندازی کند که به آن امکان نظارت بر ترافیک شبکه را می‌دهد. فقط درصورتی‌که به منبع اعتماد دارید قبول کنید. وقتی VPN فعال باشد، &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; در صفحه‌نمایش نشان داده می‌شود."</string>
     <string name="legacy_title" msgid="192936250066580964">"‏VPN متصل است"</string>
     <string name="session" msgid="6470628549473641030">"جلسه:"</string>
     <string name="duration" msgid="3584782459928719435">"مدت زمان:"</string>
diff --git a/packages/VpnDialogs/res/values-fi/strings.xml b/packages/VpnDialogs/res/values-fi/strings.xml
index 91c918a..8abca06 100644
--- a/packages/VpnDialogs/res/values-fi/strings.xml
+++ b/packages/VpnDialogs/res/values-fi/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Yhteyspyyntö"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> haluaa tehdä asetukset VPN-yhteydellä, jonka kautta sovellus voi valvoa verkkoliikennettä. Hyväksy vain, jos lähde on luotettava. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; näkyy ruudun yläreunassa, kun VPN on käytössä."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> haluaa muodostaa VPN-yhteyden, jonka avulla se voi valvoa verkkoliikennettä. Salli tämä vain, jos luotat lähteeseen. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; näkyy näytölläsi, kun VPN on aktiivinen."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN on yhdistetty"</string>
     <string name="session" msgid="6470628549473641030">"Käyttökerta"</string>
     <string name="duration" msgid="3584782459928719435">"Kesto:"</string>
diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
index aa86c7c..876111c 100644
--- a/packages/VpnDialogs/res/values-fr-rCA/strings.xml
+++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Demande de connexion"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> veut configurer une connexion RPV qui permet de surveiller le trafic réseau. N\'acceptez que si vous faites confiance à la source. &lt;br /&gt;&lt;br /&gt;&lt;img src=vpn_icon/&gt; s\'affiche dans le haut de votre écran lorsqu\'une connexion  RPV est active."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> veut configurer une connexion RPV qui permet de surveiller le trafic réseau. N\'acceptez que si vous faites confiance à la source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; s\'affiche dans le haut de votre écran lorsqu\'une connexion RPV est active."</string>
     <string name="legacy_title" msgid="192936250066580964">"RPV connecté"</string>
     <string name="session" msgid="6470628549473641030">"Session :"</string>
     <string name="duration" msgid="3584782459928719435">"Durée :"</string>
diff --git a/packages/VpnDialogs/res/values-fr/strings.xml b/packages/VpnDialogs/res/values-fr/strings.xml
index 7180119..27ebfb0 100644
--- a/packages/VpnDialogs/res/values-fr/strings.xml
+++ b/packages/VpnDialogs/res/values-fr/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Demande de connexion"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> souhaite configurer une connexion VPN qui lui permet de surveiller le trafic réseau. N\'acceptez que si vous faites confiance à la source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; s\'affiche en haut de votre écran lorsqu\'une connexion VPN est active."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> souhaite configurer une connexion VPN qui lui permet de surveiller le trafic réseau. N\'acceptez que si vous faites confiance à la source. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; s\'affiche à l\'écran lorsqu\'un VPN est actif."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN connecté"</string>
     <string name="session" msgid="6470628549473641030">"Session :"</string>
     <string name="duration" msgid="3584782459928719435">"Durée :"</string>
diff --git a/packages/VpnDialogs/res/values-gl/strings.xml b/packages/VpnDialogs/res/values-gl/strings.xml
index 8a66d08..cd8ee8d 100644
--- a/packages/VpnDialogs/res/values-gl/strings.xml
+++ b/packages/VpnDialogs/res/values-gl/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitude de conexión"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quere configurar unha conexión VPN que lle permite controlar o tráfico da rede. Acepta soamente se confías na fonte. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece na parte superior da pantalla cando se activa a VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"A aplicación <xliff:g id="APP">%s</xliff:g> quere configurar unha conexión VPN que lle permita supervisar o tráfico de rede. Acepta só se confías nela. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece na pantalla cando a VPN está activa."</string>
     <string name="legacy_title" msgid="192936250066580964">"A VPN está conectada"</string>
     <string name="session" msgid="6470628549473641030">"Sesión:"</string>
     <string name="duration" msgid="3584782459928719435">"Duración:"</string>
diff --git a/packages/VpnDialogs/res/values-gu/strings.xml b/packages/VpnDialogs/res/values-gu/strings.xml
index 961711c..b5a8831 100644
--- a/packages/VpnDialogs/res/values-gu/strings.xml
+++ b/packages/VpnDialogs/res/values-gu/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"કનેક્શન વિનંતી"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> VPN કનેક્શન સેટ કરવા માગે છે જે તેને નેટવર્ક ટ્રાફિક મૉનિટર કરવાની મંજૂરી આપે છે. જો તમને સ્રોત પર વિશ્વાસ હોય તો જ સ્વીકારો. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; તમારી સ્ક્રીનની ટોચ પર ત્યારે દેખાય છે જ્યારે VPN સક્રિય હોય છે."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> એક એવું VPN કનેક્શન સેટ કરવા માગે છે કે જે તેને નેટવર્ક ટ્રાફિકનું નિરીક્ષણ કરવાની મંજૂરી આપતું હોય. જો તમને સૉર્સ પર વિશ્વાસ હોય તો જ સ્વીકારો. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; તમારી સ્ક્રીન પર ત્યારે દેખાય છે, જ્યારે VPN સક્રિય હોય છે."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN કનેક્ટ કરેલું છે"</string>
     <string name="session" msgid="6470628549473641030">"સત્ર:"</string>
     <string name="duration" msgid="3584782459928719435">"અવધિ:"</string>
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index eed0858..c9c65d5 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"कनेक्शन अनुरोध"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> वीपीएन कनेक्‍शन सेट अप करना चाहता है, जिससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. इसकी मंज़ूरी तभी दें जब आपको इस पर भरोसा हो. वीपीएन चालू होने पर &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; आपकी स्क्रीन के सबसे ऊपर दिखाई देता है."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> को वीपीएन कनेक्शन सेट अप करने की अनुमति चाहिए. इससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. अनुमति तब दें, जब आपको ऐप्लिकेशन पर भरोसा हो. वीपीएन चालू होने पर, आपकी स्क्रीन पर &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; दिखेगा."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN कनेक्‍ट है"</string>
     <string name="session" msgid="6470628549473641030">"सत्र:"</string>
     <string name="duration" msgid="3584782459928719435">"अवधि:"</string>
diff --git a/packages/VpnDialogs/res/values-hr/strings.xml b/packages/VpnDialogs/res/values-hr/strings.xml
index aa9e436..576d997 100644
--- a/packages/VpnDialogs/res/values-hr/strings.xml
+++ b/packages/VpnDialogs/res/values-hr/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Zahtjev za povezivanje"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> želi postaviti VPN vezu pomoću koje će moći nadzirati mrežni promet. Prihvatite samo ako smatrate izvor pouzdanim. Kada je VPN aktivan, pri vrhu zaslona prikazuje se &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi postaviti VPN vezu pomoću koje će moći nadzirati mrežni promet. Prihvatite samo ako smatrate izvor pouzdanim. Kad je VPN aktivan, na zaslonu se prikazuje ikona &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN je spojen"</string>
     <string name="session" msgid="6470628549473641030">"Sesija"</string>
     <string name="duration" msgid="3584782459928719435">"Trajanje:"</string>
diff --git a/packages/VpnDialogs/res/values-hu/strings.xml b/packages/VpnDialogs/res/values-hu/strings.xml
index 703aa79..69b999f 100644
--- a/packages/VpnDialogs/res/values-hu/strings.xml
+++ b/packages/VpnDialogs/res/values-hu/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Kapcsolódási kérés"</string>
     <string name="warning" msgid="809658604548412033">"A(z) <xliff:g id="APP">%s</xliff:g> VPN kapcsolatot akar beállítani, amelynek segítségével figyelheti a hálózati forgalmat. Csak akkor fogadja el, ha megbízik a forrásban. &lt;br /&gt; &lt;br /&gt; Amikor a VPN aktív, &lt;img src=vpn_icon /&gt; ikon jelenik meg a képernyő tetején."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"A(z) <xliff:g id="APP">%s</xliff:g> alkalmazás VPN-kapcsolatot szeretne beállítani, amely segítségével figyelheti a hálózati forgalmat. Csak akkor fogadja el, ha megbízik a forrásban. &lt;br /&gt; &lt;br /&gt; Amikor aktív a VPN, a következő ikon látható a képernyőn: &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"A VPN csatlakoztatva van"</string>
     <string name="session" msgid="6470628549473641030">"Munkamenet:"</string>
     <string name="duration" msgid="3584782459928719435">"Időtartam:"</string>
diff --git a/packages/VpnDialogs/res/values-hy/strings.xml b/packages/VpnDialogs/res/values-hy/strings.xml
index c296c85..d2a6d42 100644
--- a/packages/VpnDialogs/res/values-hy/strings.xml
+++ b/packages/VpnDialogs/res/values-hy/strings.xml
@@ -17,7 +17,8 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Միացման հայց"</string>
-    <string name="warning" msgid="809658604548412033">"«<xliff:g id="APP">%s</xliff:g>» հավելվածը ցանկանում է VPN կապ հաստատել՝ ցանցային երթևեկը հսկելու համար: Թույլատրեք, միայն եթե վստահում եք աղբյուրին: Երբ VPN-ն ակտիվ լինի, ձեր էկրանի վերին հատվածում կհայտնվի &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; պատկերը:"</string>
+    <string name="warning" msgid="809658604548412033">"«<xliff:g id="APP">%s</xliff:g>» հավելվածը ցանկանում է VPN կապ հաստատել՝ ցանցային երթևեկը հսկելու համար: Թույլատրեք, միայն եթե վստահում եք աղբյուրին։ Երբ VPN-ն ակտիվ լինի, ձեր էկրանի վերին հատվածում կհայտնվի &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; պատկերը:"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> հավելվածն ուզում է միանալ VPN-ի ցանցին՝ թրաֆիկին հետևելու համար։ Թույլատրեք, միայն եթե վստահում եք աղբյուրին։ Երբ VPN-ն ակտիվացված լինի, &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; պատկերակը կհայտնվի ձեր էկրանին։"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN-ը կապակցված է"</string>
     <string name="session" msgid="6470628549473641030">"Աշխատաշրջան`"</string>
     <string name="duration" msgid="3584782459928719435">"Տևողությունը՝"</string>
@@ -25,7 +26,7 @@
     <string name="data_received" msgid="4062776929376067820">"Ստացվել է՝"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> բայթ / <xliff:g id="NUMBER_1">%2$s</xliff:g> փաթեթ"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"Չի հաջողվում միանալ միշտ միացված VPN-ին"</string>
-    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g>-ն այնպես է կարգավորված, որ միշտ միացած մնա, սակայն ներկայումս կապակցման խնդիր կա: Ձեր հեռախոսը կօգտագործի հանրային ցանցը, մինչև նորից կարողանա միանալ <xliff:g id="VPN_APP_1">%1$s</xliff:g>-ին:"</string>
+    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g>-ն այնպես է կարգավորված, որ միշտ միացած մնա, սակայն ներկայումս կապակցման խնդիր կա: Ձեր հեռախոսը կօգտագործի հանրային ցանցը, մինչև նորից կարողանա միանալ <xliff:g id="VPN_APP_1">%1$s</xliff:g>-ին։"</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ն այնպես է կարգավորված, որ միշտ միացած մնա, սակայն ներկայումս կապակցման խնդիր կա: Մինչև VPN-ը նորից չմիանա, դուք կապ չեք ունենա:"</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Փոխել VPN-ի կարգավորումները"</string>
diff --git a/packages/VpnDialogs/res/values-in/strings.xml b/packages/VpnDialogs/res/values-in/strings.xml
index 18ef372a..059008f 100644
--- a/packages/VpnDialogs/res/values-in/strings.xml
+++ b/packages/VpnDialogs/res/values-in/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Permintaan sambungan"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ingin menyiapkan sambungan VPN yang memungkinkannya memantau traffic jaringan. Terima hanya jika Anda memercayai sumber. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; muncul di bagian atas layar Anda saat VPN aktif."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ingin menyiapkan koneksi VPN yang memungkinkannya memantau traffic jaringan. Hanya terima jika Anda memercayai sumbernya. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; muncul di layar bila VPN aktif."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN tersambung"</string>
     <string name="session" msgid="6470628549473641030">"Sesi:"</string>
     <string name="duration" msgid="3584782459928719435">"Durasi:"</string>
diff --git a/packages/VpnDialogs/res/values-is/strings.xml b/packages/VpnDialogs/res/values-is/strings.xml
index 70fb40f..a75371d 100644
--- a/packages/VpnDialogs/res/values-is/strings.xml
+++ b/packages/VpnDialogs/res/values-is/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Beiðni um tengingu"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vill setja upp VPN-tengingu til þess að geta fylgst með netumferð. Samþykktu þetta aðeins ef þú treystir upprunanum. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; birtist efst á skjánum þegar VPN er virkt."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> vill setja upp VPN-tengingu til að fylgjast með netumferð. Ekki samþykkja þú treystir upprunanum. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; birtist á skjánum hjá þér þegar VPN er virkt."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN er tengt"</string>
     <string name="session" msgid="6470628549473641030">"Lota:"</string>
     <string name="duration" msgid="3584782459928719435">"Tímalengd:"</string>
diff --git a/packages/VpnDialogs/res/values-it/strings.xml b/packages/VpnDialogs/res/values-it/strings.xml
index 2602493..c443c51 100644
--- a/packages/VpnDialogs/res/values-it/strings.xml
+++ b/packages/VpnDialogs/res/values-it/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Richiesta di connessione"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vuole impostare una connessione VPN che le consenta di monitorare il traffico di rete. Accetta soltanto se ritieni la fonte attendibile. Quando la connessione VPN è attiva, nella parte superiore dello schermo viene visualizzata l\'icona &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> vuole configurare una connessione VPN che le consenta di monitorare il traffico di rete. Accetta soltanto se ritieni la fonte attendibile. Quando la connessione VPN è attiva, sullo schermo viene visualizzata l\'icona &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN connessa"</string>
     <string name="session" msgid="6470628549473641030">"Sessione:"</string>
     <string name="duration" msgid="3584782459928719435">"Durata:"</string>
diff --git a/packages/VpnDialogs/res/values-iw/strings.xml b/packages/VpnDialogs/res/values-iw/strings.xml
index ebabd4e..81903d2 100644
--- a/packages/VpnDialogs/res/values-iw/strings.xml
+++ b/packages/VpnDialogs/res/values-iw/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"בקשת חיבור"</string>
     <string name="warning" msgid="809658604548412033">"‏<xliff:g id="APP">%s</xliff:g> רוצה להגדיר חיבור VPN שיאפשר לו לפקח על תעבורת הרשת. אשר את הבקשה רק אם אתה נותן אמון במקור. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; מופיע בחלק העליון של המסך כאשר VPN פעיל."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"‏האפליקציה <xliff:g id="APP">%s</xliff:g> מבקשת להגדיר חיבור VPN שבאמצעותו היא תנהל מעקב אחר התנועה ברשת. יש לאשר את הבקשה רק אם המקור נראה לך אמין. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; מופיע על המסך כאשר חיבור ה-VPN פעיל."</string>
     <string name="legacy_title" msgid="192936250066580964">"‏VPN מחובר"</string>
     <string name="session" msgid="6470628549473641030">"הפעלה"</string>
     <string name="duration" msgid="3584782459928719435">"משך:"</string>
diff --git a/packages/VpnDialogs/res/values-ja/strings.xml b/packages/VpnDialogs/res/values-ja/strings.xml
index 8480692..e03e9d3 100644
--- a/packages/VpnDialogs/res/values-ja/strings.xml
+++ b/packages/VpnDialogs/res/values-ja/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"接続リクエスト"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> がネットワーク トラフィックを監視するため VPN 接続をセットアップしようとしています。信頼できるソースである場合にのみ許可してください。&lt;br /&gt; &lt;br /&gt; VPN がアクティブになると画面の上部に &lt;img src=vpn_icon /&gt; が表示されます。"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> は、ネットワーク トラフィックを監視できるよう、VPN 接続を設定するよう求めています。ソースを信頼できる場合のみ、許可してください。VPN が有効になると、画面に &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; が表示されます。"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN接続済み"</string>
     <string name="session" msgid="6470628549473641030">"セッション:"</string>
     <string name="duration" msgid="3584782459928719435">"期間:"</string>
diff --git a/packages/VpnDialogs/res/values-ka/strings.xml b/packages/VpnDialogs/res/values-ka/strings.xml
index e5a0753..9c4388e 100644
--- a/packages/VpnDialogs/res/values-ka/strings.xml
+++ b/packages/VpnDialogs/res/values-ka/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"კავშირის მოთხოვნა"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> სურს დააყენოს VPN კავშირი, რაც ქსელის ტრაფიკის მონიტორინგის საშუალებას იძლევა. მიიღოთ მხოლოდ ისეთ შემთხვევაში, თუ წყაროს ენდობით. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; თქვენი ეკრანის სიის თავში გამოჩნდება, როდესაც VPN აქტიურია."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>-ს სურს დააყენოს VPN კავშირი, რაც ქსელის ტრაფიკის მონიტორინგის საშუალებას იძლევა. დათანხმდით მხოლოდ იმ შემთხვევაში, თუ წყაროს ენდობით. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; თქვენს ეკრანზე გამოჩნდება, როდესაც VPN აქტიურია."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN დაკავშირებულია"</string>
     <string name="session" msgid="6470628549473641030">"სესია:"</string>
     <string name="duration" msgid="3584782459928719435">"ხანგრძლივობა:"</string>
diff --git a/packages/VpnDialogs/res/values-kk/strings.xml b/packages/VpnDialogs/res/values-kk/strings.xml
index 79f79c3..9a499d3 100644
--- a/packages/VpnDialogs/res/values-kk/strings.xml
+++ b/packages/VpnDialogs/res/values-kk/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Байланысты сұрау"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> VPN байланысын орнатқысы келеді, бұл оған желілік трафикті бақылауға мүмкіндік береді. Көзге сенсеңіз ғана қабылдаңыз. VPN белсенді болғанда экранның жоғарғы жағында &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; көрсетіледі."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> қолданбасы VPN байланысын орнатқысы келеді, бұл оған желі трафигін бақылауға мүмкіндік береді. Сұрауды қабылдамас бұрын, дереккөздің сенімді екеніне көз жеткізіңіз. VPN белсенді болған кезде, экранда &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; белгішесі пайда болады."</string>
     <string name="legacy_title" msgid="192936250066580964">"ВЖЖ қосылған"</string>
     <string name="session" msgid="6470628549473641030">"Сессия:"</string>
     <string name="duration" msgid="3584782459928719435">"Ұзақтығы:"</string>
diff --git a/packages/VpnDialogs/res/values-km/strings.xml b/packages/VpnDialogs/res/values-km/strings.xml
index 06f34db..0ed2e84b 100644
--- a/packages/VpnDialogs/res/values-km/strings.xml
+++ b/packages/VpnDialogs/res/values-km/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"សំណើ​សុំ​ការ​តភ្ជាប់"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ចង់​បង្កើត​ការ​តភ្ជាប់ VPN ដែល​អនុញ្ញាត​ឲ្យ​វា​ត្រួតពិនិត្យ​ចរាចរ​បណ្ដាញ។ ព្រម​ទទួល ប្រសិនបើ​អ្នក​ទុកចិត្ត​លើ​ប្រភព​តែប៉ុណ្ណោះ។ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; នឹង​លេចឡើង​នៅ​ផ្នែក​ខាងលើ​នៃ​អេក្រង់​របស់​អ្នក ពេល VPN សកម្ម។"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ចង់រៀបចំការតភ្ជាប់ VPN ដែលអនុញ្ញាតឱ្យវាត្រួតពិនិត្យ​ចរាចរណ៍បណ្តាញ។ យល់ព្រម ប្រសិនបើអ្នកជឿទុកចិត្តលើប្រភពនេះតែប៉ុណ្ណោះ។ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; បង្ហាញនៅលើអេក្រង់របស់អ្នក នៅពេល VPN កំពុងដំណើរការ។"</string>
     <string name="legacy_title" msgid="192936250066580964">"បា​ន​ភ្ជាប់ VPN"</string>
     <string name="session" msgid="6470628549473641030">"សម័យ៖"</string>
     <string name="duration" msgid="3584782459928719435">"ថិរវេលា៖"</string>
diff --git a/packages/VpnDialogs/res/values-kn/strings.xml b/packages/VpnDialogs/res/values-kn/strings.xml
index 040cd6c..6308f18 100644
--- a/packages/VpnDialogs/res/values-kn/strings.xml
+++ b/packages/VpnDialogs/res/values-kn/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"ಸಂಪರ್ಕ ವಿನಂತಿ"</string>
     <string name="warning" msgid="809658604548412033">"ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಅನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಲು ಅನುಮತಿಸುವಂತಹ VPN ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಸಲು <xliff:g id="APP">%s</xliff:g> ಬಯಸುತ್ತದೆ. ನೀವು ಮೂಲವನ್ನು ನಂಬಿದರೆ ಮಾತ್ರ ಸಮ್ಮತಿಸಿ. VPN ಸಕ್ರಿಯವಾಗಿರುವಾಗ ನಿಮ್ಮ ಪರದೆಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ಗೋರಿಸುತ್ತದೆ."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಅನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಲು ಅನುಮತಿಸುವಂತಹ VPN ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಸಲು <xliff:g id="APP">%s</xliff:g> ಬಯಸುತ್ತದೆ. ನಿಮಗೆ ಮೂಲದ ಮೇಲೆ ನಂಬಿಕೆ ಇದ್ದರೆ ಮಾತ್ರ ಸ್ವೀಕರಿಸಿ. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN ಸಕ್ರಿಯವಾದ ನಂತರ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುತ್ತದೆ."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="session" msgid="6470628549473641030">"ಸೆಷನ್:"</string>
     <string name="duration" msgid="3584782459928719435">"ಅವಧಿ:"</string>
diff --git a/packages/VpnDialogs/res/values-ko/strings.xml b/packages/VpnDialogs/res/values-ko/strings.xml
index 6ad4976..6e179bb 100644
--- a/packages/VpnDialogs/res/values-ko/strings.xml
+++ b/packages/VpnDialogs/res/values-ko/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"연결 요청"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>에서 네트워크 트래픽을 모니터링하도록 허용하는 VPN 연결을 설정하려고 합니다. 출처를 신뢰할 수 있는 경우에만 수락하세요. VPN이 활성화되면 &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;이 화면 위에 표시됩니다."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>에서 네트워크 트래픽을 모니터링할 수 있도록 VPN 연결을 설정하려고 합니다. 소스를 신뢰할 수 있는 경우에만 수락하세요. VPN이 활성 상태일 때는 &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; 아이콘이 화면에 표시됩니다."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN이 연결되었습니다."</string>
     <string name="session" msgid="6470628549473641030">"세션:"</string>
     <string name="duration" msgid="3584782459928719435">"기간:"</string>
diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml
index 23c9be8..31f9e2d 100644
--- a/packages/VpnDialogs/res/values-ky/strings.xml
+++ b/packages/VpnDialogs/res/values-ky/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Туташуу сурамы"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> тармактык трафикти көзөмөлдөөгө уруксат берген VPN туташуусун орноткусу келет. Аны булакка ишенсеңиз гана кабыл алыңыз. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN иштеп турганда экраныңыздын жогору жагынан көрүнөт."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> тармак трафигин көзөмөлдөөгө уруксат берген VPN байланышын орноткусу келет. Булакка ишенсеңиз гана кабыл алыңыз. VPN иштеп жатканда, экраныңызда &lt;br /&gt; &lt;br /&gt; &amp;It;img src=vpn_icon /&gt; көрүнөт."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN байланышта"</string>
     <string name="session" msgid="6470628549473641030">"Сессия:"</string>
     <string name="duration" msgid="3584782459928719435">"Узактыгы:"</string>
diff --git a/packages/VpnDialogs/res/values-lo/strings.xml b/packages/VpnDialogs/res/values-lo/strings.xml
index c591308..cec69f0 100644
--- a/packages/VpnDialogs/res/values-lo/strings.xml
+++ b/packages/VpnDialogs/res/values-lo/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"ການ​ຮ້ອງ​ຂໍ​ການ​ເຊື່ອມ​ຕໍ່"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ຕ້ອງ​ການ​ຕັ້​ງ​ຄ່າ​ການ​ເຊື່ອມ​ຕໍ່ VPN ທີ່​ອະ​ນຸ​ຍາດ​ໃຫ້​ຕິດ​ຕາມ​ທຣາບ​ຟິກ​ເຄືອ​ຂ່າຍ​ໄດ້. ​ທ່ານ​​ຄວນ​​ຍິນຍອມ​ສະ​ເພາະ​ໃນ​ກໍ​ລະ​ນີ​ທີ່​ທ່ານ​ເຊື່ອ​ຖື​ແຫລ່ງ​ຂໍ້​ມູນ​ເທົ່າ​ນັ້ນ. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ຈະ​ປາ​ກົດ​ຢູ່​ດ້ານ​ເທິງ​ຂອງ​ໜ້າ​ຈໍ​ເມື່ອ​ມີ​ການ​ເປີດ​ໃຊ້ VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ຕ້ອງການຕັ້ງຄ່າການເຊື່ອມຕໍ່ VPN ທີ່ອະນຸຍາດໃຫ້ມັນກວດກາການ​ຈາ​ລະ​ຈອນ​ເຄືອ​ຂ່າ​ຍໄດ້. ໃຫ້ຍອມຮັບສະເພາະໃນກໍລະນີທີ່ທ່ານເຊື່ອຖືແຫຼ່ງທີ່ມາເທົ່ານັ້ນ. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ຈະປາກົດຢູ່ໜ້າຈໍຂອງທ່ານເມື່ອເປີດໃຊ້ VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"ເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
     <string name="session" msgid="6470628549473641030">"ເຊສຊັນ:"</string>
     <string name="duration" msgid="3584782459928719435">"ໄລຍະເວລາ:"</string>
diff --git a/packages/VpnDialogs/res/values-lt/strings.xml b/packages/VpnDialogs/res/values-lt/strings.xml
index 8846310..97abd0d 100644
--- a/packages/VpnDialogs/res/values-lt/strings.xml
+++ b/packages/VpnDialogs/res/values-lt/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Ryšio užklausa"</string>
     <string name="warning" msgid="809658604548412033">"„<xliff:g id="APP">%s</xliff:g>“ nori nustatyti VPN ryšį, kad galėtų stebėti tinklo srautą. Sutikite, tik jei pasitikite šaltiniu. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; rodoma ekrano viršuje, kai VPN aktyvus."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Programa „<xliff:g id="APP">%s</xliff:g>“ nori nustatyti VPN ryšį, kad galėtų stebėti tinklo srautą. Sutikite, tik jei pasitikite šaltiniu. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; piktograma rodoma ekrane, kai VPN aktyvus."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN prijungtas"</string>
     <string name="session" msgid="6470628549473641030">"Sesija"</string>
     <string name="duration" msgid="3584782459928719435">"Trukmė:"</string>
diff --git a/packages/VpnDialogs/res/values-lv/strings.xml b/packages/VpnDialogs/res/values-lv/strings.xml
index 07625b6..6341fbd 100644
--- a/packages/VpnDialogs/res/values-lv/strings.xml
+++ b/packages/VpnDialogs/res/values-lv/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Savienojuma pieprasījums"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vēlas izveidot VPN savienojumu, kas ļaus pārraudzīt tīkla datplūsmu. Piekrītiet tikai tad, ja uzticaties avotam. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; tiek rādīta ekrāna augšdaļā, kad darbojas VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Lietotne <xliff:g id="APP">%s</xliff:g> vēlas izveidot VPN savienojumu, kas ļaus pārraudzīt tīkla datplūsmu. Piekrītiet tikai tad, ja uzticaties avotam. &lt;br /&gt; &lt;br /&gt; Ekrānā tiek rādīta ikona &lt;img src=vpn_icon /&gt;, kad darbojas VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"Ir izveidots savienojums ar VPN"</string>
     <string name="session" msgid="6470628549473641030">"Sesija:"</string>
     <string name="duration" msgid="3584782459928719435">"Ilgums:"</string>
diff --git a/packages/VpnDialogs/res/values-mk/strings.xml b/packages/VpnDialogs/res/values-mk/strings.xml
index b5a64f2..689d028 100644
--- a/packages/VpnDialogs/res/values-mk/strings.xml
+++ b/packages/VpnDialogs/res/values-mk/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Барање за поврзување"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> сака да постави поврзување со ВПН коешто му дозволува да го набљудува сообраќајот на мрежата. Прифатете само доколку му верувате на изворот. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; се појавува на врвот на екранот кога ВПН е активна."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> сака да постави поврзување со VPN што ќе дозволи да го набљудува сообраќајот на мрежата. Прифатете само ако му верувате на изворот. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ќе се појави на екранот кога ќе се активира VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN е поврзана"</string>
     <string name="session" msgid="6470628549473641030">"Сесија:"</string>
     <string name="duration" msgid="3584782459928719435">"Времетраење:"</string>
@@ -30,7 +31,7 @@
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Променете ги поставките за VPN"</string>
     <string name="configure" msgid="4905518375574791375">"Конфигурирај"</string>
-    <string name="disconnect" msgid="971412338304200056">"Исклучи"</string>
+    <string name="disconnect" msgid="971412338304200056">"Прекини врска"</string>
     <string name="open_app" msgid="3717639178595958667">"Отвори ја апликацијата"</string>
     <string name="dismiss" msgid="6192859333764711227">"Отфрли"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ml/strings.xml b/packages/VpnDialogs/res/values-ml/strings.xml
index 680d0ef..8284a78 100644
--- a/packages/VpnDialogs/res/values-ml/strings.xml
+++ b/packages/VpnDialogs/res/values-ml/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"കണക്ഷൻ അഭ്യർത്ഥന"</string>
     <string name="warning" msgid="809658604548412033">"നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കാൻ അനുവദിക്കുന്ന ഒരു VPN കണക്ഷൻ <xliff:g id="APP">%s</xliff:g> സജ്ജീകരിക്കേണ്ടതുണ്ട്. ഉറവിടം പരിചിതമാണെങ്കിൽ മാത്രം അംഗീകരിക്കുക. VPN സജീവമാകുമ്പോൾ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; നിങ്ങളുടെ സ്ക്രീനിന്റെ മുകളിൽ ദൃശ്യമാകുന്നു."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"നെറ്റ്‌വർക്ക് ട്രാഫിക് നിരീക്ഷിക്കാൻ അനുവദിക്കുന്ന ഒരു VPN കണക്ഷൻ സജ്ജീകരിക്കാൻ <xliff:g id="APP">%s</xliff:g> താൽപ്പര്യപ്പെടുന്നു. നിങ്ങൾ ഉറവിടം വിശ്വസിക്കുന്നുണ്ടെങ്കിൽ മാത്രം അംഗീകരിക്കുക. VPN സജീവമാകുമ്പോൾ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; നിങ്ങളുടെ സ്‌ക്രീനിൽ ദൃശ്യമാകും."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="session" msgid="6470628549473641030">"സെഷൻ:"</string>
     <string name="duration" msgid="3584782459928719435">"സമയദൈര്‍ഘ്യം:"</string>
diff --git a/packages/VpnDialogs/res/values-mn/strings.xml b/packages/VpnDialogs/res/values-mn/strings.xml
index 9aa104a..1dd4c15 100644
--- a/packages/VpnDialogs/res/values-mn/strings.xml
+++ b/packages/VpnDialogs/res/values-mn/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Холболтын хүсэлт"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> нь сүлжээний трафикыг хянах боломж бүхий VPN холболт үүсгэхийг хүсэж байна. Та зөвхөн эх үүсвэрт итгэж байгаа бол зөвшөөрнө үү. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; таны дэлгэц дээр VPN идэвхтэй үед гарч ирнэ."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> нь түүнд сүлжээний ачааллыг хянах боломжийг олгодог VPN холболт тохируулахыг хүсэж байна. Зөвхөн та эх сурвалжид итгэдэг тохиолдолд зөвшөөрнө үү. VPN идэвхтэй үед таны дэлгэц дээр &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; харагдана."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN холбогдов"</string>
     <string name="session" msgid="6470628549473641030">"Сешн:"</string>
     <string name="duration" msgid="3584782459928719435">"Үргэлжлэх хугацаа:"</string>
diff --git a/packages/VpnDialogs/res/values-mr/strings.xml b/packages/VpnDialogs/res/values-mr/strings.xml
index 41d7429..22fb502 100644
--- a/packages/VpnDialogs/res/values-mr/strings.xml
+++ b/packages/VpnDialogs/res/values-mr/strings.xml
@@ -18,18 +18,19 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"कनेक्‍शन विनंती"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> नेटवर्क रहदारीचे परीक्षण करण्‍यासाठी त्यास अनुमती देणारे VPN कनेक्‍शन सेट करू इच्‍छितो. तुम्हाला स्रोत विश्वसनीय वाटत असेल तरच स्वीकार करा. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN सक्रिय असताना आपल्‍या स्क्रीनच्या शीर्षावर दिसते."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ला नेटवर्क ट्रॅफिकवर लक्ष ठेवण्याची अनुमती देणारे VPN कनेक्‍शन सेट करायचे आहे. तुमचा स्रोतावर विश्वास असेल तरच स्वीकारा. VPN अ‍ॅक्टिव्ह असल्यास, तुमच्या स्क्रीनवर &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; दिसते."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN कनेक्‍ट केले"</string>
     <string name="session" msgid="6470628549473641030">"सत्र:"</string>
     <string name="duration" msgid="3584782459928719435">"कालावधी:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"प्रेषित:"</string>
     <string name="data_received" msgid="4062776929376067820">"प्राप्त झाले:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> बाइट / <xliff:g id="NUMBER_1">%2$s</xliff:g> पॅकेट"</string>
-    <string name="always_on_disconnected_title" msgid="1906740176262776166">"कायम चालू असलेल्या VPN शी कनेक्ट करू शकत नाही"</string>
+    <string name="always_on_disconnected_title" msgid="1906740176262776166">"कायम सुरू असलेल्या VPN शी कनेक्ट करू शकत नाही"</string>
     <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> हे पूर्ण वेळ कनेक्ट राहण्यासाठी सेट अप केलेले आहे, पण हे आता कनेक्ट होऊ शकत नाही. <xliff:g id="VPN_APP_1">%1$s</xliff:g> शी पुन्हा कनेक्ट होईपर्यंत तुमचा फोन सार्वजनिक नेटवर्क वापरेल."</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> हे पूर्ण वेळ कनेक्ट राहण्यासाठी सेट अप केलेले आहे, पण हे आता कनेक्ट होऊ शकत नाही. VPN पुन्हा कनेक्ट होईपर्यंत तुमच्याकडे कनेक्शन नसेल."</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN सेटिंग्ज बदला"</string>
-    <string name="configure" msgid="4905518375574791375">"कॉन्फिगर करा"</string>
+    <string name="configure" msgid="4905518375574791375">"कॉंफिगर करा"</string>
     <string name="disconnect" msgid="971412338304200056">"‍डिस्कनेक्ट करा"</string>
     <string name="open_app" msgid="3717639178595958667">"अ‍ॅप उघडा"</string>
     <string name="dismiss" msgid="6192859333764711227">"डिसमिस करा"</string>
diff --git a/packages/VpnDialogs/res/values-ms/strings.xml b/packages/VpnDialogs/res/values-ms/strings.xml
index b489f2e..c9961d2 100644
--- a/packages/VpnDialogs/res/values-ms/strings.xml
+++ b/packages/VpnDialogs/res/values-ms/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Permintaan sambungan"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ingin menyediakan sambungan VPN yang membenarkan apl memantau trafik rangkaian. Terima hanya jika anda mempercayai sumber. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; terpapar pada bahagian atas skrin anda apabila VPN aktif."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ingin menyediakan sambungan VPN yang membenarkan apl tersebut memantau trafik rangkaian. Hanya terima jika anda mempercayai sumber tersebut. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; muncul pada skrin anda apabila VPN aktif."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN telah disambungkan"</string>
     <string name="session" msgid="6470628549473641030">"Sesi:"</string>
     <string name="duration" msgid="3584782459928719435">"Tempoh:"</string>
diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml
index 9d60ff4..36348c8 100644
--- a/packages/VpnDialogs/res/values-my/strings.xml
+++ b/packages/VpnDialogs/res/values-my/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"ချိတ်ဆက်ရန် တောင်းဆိုချက်"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> က ကွန်ရက် လုပ်ငန်းကို စောင့်ကြည့်ခွင့် ပြုမည့် VPN ချိတ်ဆက်မှုကို ထူထောင်လိုသည်။ ရင်းမြစ်ကို သင်က ယုံကြည်မှသာ လက်ခံပါ။ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; မှာ VPN အလုပ်လုပ်နေလျှင် သင်၏ မျက်နှာပြင် ထိပ်မှာ ပေါ်လာမည်။"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> က ကွန်ရက်ဒေတာ စီးဆင်းမှုကို စောင့်ကြည့်ရန် ခွင့်ပြုသည့် VPN ချိတ်ဆက်မှုကို စနစ်ထည့်သွင်းလိုသည်။ ဤရင်းမြစ်ကို သင်ယုံကြည်မှသာ လက်ခံပါ။ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; သည် VPN ဖွင့်ထားသောအခါ သင့်ဖန်သားပြင်တွင် ပေါ်ပါသည်။"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPNနှင့်ချိတ်ဆက်ထားသည်"</string>
     <string name="session" msgid="6470628549473641030">"သတ်မှတ်ပေးထားသည့်အချိန်:"</string>
     <string name="duration" msgid="3584782459928719435">"အချိန်ကာလ-"</string>
@@ -30,7 +31,7 @@
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ဆက်တင်များ ပြောင်းရန်"</string>
     <string name="configure" msgid="4905518375574791375">"ပုံပေါ်စေသည်"</string>
-    <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်ခြင်းရပ်ရန်"</string>
+    <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
     <string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string>
     <string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-nb/strings.xml b/packages/VpnDialogs/res/values-nb/strings.xml
index be572d4..14c84d7 100644
--- a/packages/VpnDialogs/res/values-nb/strings.xml
+++ b/packages/VpnDialogs/res/values-nb/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Tilkoblingsforespørsel"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ønsker å bruke en VPN-tilkobling som tillater at appen overvåker nettverkstrafikken. Du bør bare godta dette hvis du stoler på kilden. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; vises øverst på skjermen din når VPN er aktivert."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> vil konfigurere en VPN-tilkobling som lar appen overvåke nettverkstrafikk. Du bør bare godta dette hvis du stoler på kilden. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; vises på skjermen når VPN er aktivert."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN er tilkoblet"</string>
     <string name="session" msgid="6470628549473641030">"Økt:"</string>
     <string name="duration" msgid="3584782459928719435">"Varighet:"</string>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index b716c35..2a5648d 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"जडान अनुरोध"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ले नेटवर्क यातायात अनुगमन गर्न अनुमति दिने VPN जडान स्थापना गर्न चाहन्छ। तपाईँले स्रोत भरोसा छ भने मात्र स्वीकार गर्नुहोस्। &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; जब VPN सक्रिय हुन्छ आफ्नो स्क्रिनको माथि देखा पर्छन्।"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ले कुनै VPN कनेक्सन सेटअप गर्न चाहन्छ। यसको सहायताले यो एप नेटवर्क ट्राफिकको निगरानी राख्न सक्छ। तपाईं यो एपमाथि विश्वास गर्नुहुन्छ भने मात्र स्वीकार गर्नुहोस्। VPN सक्रिय हुँदा तपाईंको स्क्रिनमा &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; देखा पर्छ।"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN जोडिएको छ"</string>
     <string name="session" msgid="6470628549473641030">"सत्र:"</string>
     <string name="duration" msgid="3584782459928719435">"अवधि:"</string>
@@ -30,7 +31,7 @@
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN सम्बन्धी सेटिङहरू परिवर्तन गर्नुहोस्"</string>
     <string name="configure" msgid="4905518375574791375">"कन्फिगर गर्नुहोस्"</string>
-    <string name="disconnect" msgid="971412338304200056">"विच्छेदन गर्नुहोस्"</string>
-    <string name="open_app" msgid="3717639178595958667">"अनुप्रयोग खोल्नुहोस्"</string>
+    <string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट गर्नुहोस्"</string>
+    <string name="open_app" msgid="3717639178595958667">"एप खोल्नुहोस्"</string>
     <string name="dismiss" msgid="6192859333764711227">"खारेज गर्नुहोस्"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml
index 8073b09..33f8a89 100644
--- a/packages/VpnDialogs/res/values-nl/strings.xml
+++ b/packages/VpnDialogs/res/values-nl/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Verbindingsverzoek"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding opzetten om netwerkverkeer te controleren. Accepteer het verzoek alleen als je de bron vertrouwt. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; wordt boven aan je scherm weergegeven wanneer VPN actief is."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding instellen waarmee de app het netwerkverkeer kan bijhouden. Accepteer dit alleen als je de bron vertrouwt. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; verschijnt op je scherm als het VPN actief is."</string>
     <string name="legacy_title" msgid="192936250066580964">"Verbinding met VPN"</string>
     <string name="session" msgid="6470628549473641030">"Sessie:"</string>
     <string name="duration" msgid="3584782459928719435">"Duur:"</string>
diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml
index f1122eb..0604b47 100644
--- a/packages/VpnDialogs/res/values-or/strings.xml
+++ b/packages/VpnDialogs/res/values-or/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"ସଂଯୋଗ ଅନୁରୋଧ"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ଏକ VPN ସଂଯୋଗ ସେଟ୍ ଅପ୍ କରିବାକୁ ଚାହେଁ, ଯାହା ଏହି ନେଟ୍‌ୱର୍କର ଟ୍ରାଫିକକୁ ମନିଟର୍ କରିବାକୁ ଅନୁମତି ଦିଏ। ଆପଣ ସୋର୍ସ ଉପରେ ବିଶ୍ୱାସ କରିବା ବଦଳରେ କେବଳ ସ୍ୱୀକାର କରନ୍ତୁ। &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN ସକ୍ରିୟ ଥିବାବେଳେ ଏହା ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍‍ର ଉପରେ ଦେଖାଯାଏ।"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ଏକ VPN ସଂଯୋଗ ସେଟ୍ ଅପ୍ କରିବାକୁ ଚାହେଁ, ଯାହା ଏହାକୁ ନେଟୱାର୍କ ଟ୍ରାଫିକ ମନିଟର୍ କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ। ଯଦି ଆପଣ ସୋର୍ସରେ ବିଶ୍ୱାସ କରୁଛନ୍ତି, ତେବେ ହିଁ କେବଳ ସ୍ୱୀକାର କରନ୍ତୁ। &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN ସକ୍ରିୟ ଥିବା ସମୟରେ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍ ଉପରେ ଦେଖାଯାଏ।"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ସଂଯୋଗ ହେଲା"</string>
     <string name="session" msgid="6470628549473641030">"ସେସନ୍‍:"</string>
     <string name="duration" msgid="3584782459928719435">"ଅବଧି:"</string>
@@ -28,7 +29,7 @@
     <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇ ରହିବା ପାଇଁ ସେଟଅପ୍‍ କରାଯାଇଛି। ଆପଣଙ୍କ ଫୋନ୍‍, <xliff:g id="VPN_APP_1">%1$s</xliff:g> ସହ କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏକ ପବ୍ଲିକ୍‍ ନେଟ୍‌ୱର୍କ ବ୍ୟବହାର କରିବ।"</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇରହିବାକୁ ସେଟଅପ୍‍ କରାଯାଇଛି, କିନ୍ତୁ ଏହା ବର୍ତ୍ତମାନ କନେକ୍ଟ କରିପାରୁ ନାହିଁ। VPN ପୁଣି କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଆପଣଙ୍କର କୌଣସି କନେକ୍ସନ୍‌ ରହିବନାହିଁ।"</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
-    <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଙ୍ଗ ବଦଳାନ୍ତୁ"</string>
+    <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ୍ ବଦଳାନ୍ତୁ"</string>
     <string name="configure" msgid="4905518375574791375">"କନଫିଗର୍‍ କରନ୍ତୁ"</string>
     <string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
     <string name="open_app" msgid="3717639178595958667">"ଆପ୍‌ ଖୋଲନ୍ତୁ"</string>
diff --git a/packages/VpnDialogs/res/values-pa/strings.xml b/packages/VpnDialogs/res/values-pa/strings.xml
index 1815f4f..d2eba0f 100644
--- a/packages/VpnDialogs/res/values-pa/strings.xml
+++ b/packages/VpnDialogs/res/values-pa/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"ਕਨੈਕਸ਼ਨ ਬੇਨਤੀ"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ਇੱਕ VPN ਕਨੈਕਸ਼ਨ ਸੈਟ ਅਪ ਕਰਨਾ ਚਾਹੁੰਦਾ ਹੈ ਜੋ ਇਸਨੂੰ ਨੈੱਟਵਰਕ ਟ੍ਰੈਫਿਕ ਦਾ ਨਿਰੀਖਣ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਕੇਵਲ ਤਾਂ ਹੀ ਸਵੀਕਾਰ ਕਰੋ ਜੇਕਰ ਤੁਸੀਂ ਸਰੋਤ ਤੇ ਭਰੋਸਾ ਕਰਦੇ ਹੋ। &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਟੌਪ ਤੇ ਪ੍ਰਗਟ ਹੁੰਦਾ ਹੈ ਜਦੋਂ VPN ਸਕਿਰਿਆ ਹੁੰਦਾ ਹੈ।"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ਕਿਸੇ ਅਜਿਹੇ VPN ਕਨੈਕਸ਼ਨ ਦਾ ਸੈੱਟਅੱਪ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ ਜੋ ਇਸਨੂੰ ਨੈੱਟਵਰਕ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦਾ ਹੈ। ਸਿਰਫ਼ ਉਦੋਂ ਹੀ ਸਵੀਕਾਰ ਕਰੋ ਜੇ ਤੁਹਾਨੂੰ ਸਰੋਤ \'ਤੇ ਭਰੋਸਾ ਹੈ। VPN ਦੇ ਕਿਰਿਆਸ਼ੀਲ ਹੋਣ \'ਤੇ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਦਾ ਹੈ।"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
     <string name="session" msgid="6470628549473641030">"ਸੈਸ਼ਨ:"</string>
     <string name="duration" msgid="3584782459928719435">"ਮਿਆਦ:"</string>
diff --git a/packages/VpnDialogs/res/values-pl/strings.xml b/packages/VpnDialogs/res/values-pl/strings.xml
index d5201d7..82161d3 100644
--- a/packages/VpnDialogs/res/values-pl/strings.xml
+++ b/packages/VpnDialogs/res/values-pl/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Żądanie połączenia"</string>
     <string name="warning" msgid="809658604548412033">"Aplikacja <xliff:g id="APP">%s</xliff:g> chce utworzyć połączenie VPN, które pozwoli jej na monitorowanie ruchu sieciowego. Zaakceptuj, tylko jeśli masz zaufanie do źródła. &lt;br /&gt; &lt;br /&gt;Gdy sieć VPN jest aktywna, u góry ekranu pojawia się &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikacja <xliff:g id="APP">%s</xliff:g> chce utworzyć połączenie VPN, które pozwoli jej na monitorowanie ruchu w sieci. Zaakceptuj, jeśli masz zaufanie do źródła. &lt;br /&gt; &lt;br Gdy sieć VPN jest aktywna, na ekranie pojawia się ikona /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"Połączono z VPN"</string>
     <string name="session" msgid="6470628549473641030">"Sesja:"</string>
     <string name="duration" msgid="3584782459928719435">"Czas trwania:"</string>
diff --git a/packages/VpnDialogs/res/values-pt-rBR/strings.xml b/packages/VpnDialogs/res/values-pt-rBR/strings.xml
index 75c1406..0d6dd0b 100644
--- a/packages/VpnDialogs/res/values-pt-rBR/strings.xml
+++ b/packages/VpnDialogs/res/values-pt-rBR/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitação de conexão"</string>
     <string name="warning" msgid="809658604548412033">"O <xliff:g id="APP">%s</xliff:g> quer configurar uma conexão VPN que permite monitorar o tráfego da rede. Aceite somente se confiar na origem. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; é exibido na parte superior da tela quando a rede VPN estiver ativa."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"O app <xliff:g id="APP">%s</xliff:g> quer definir uma conexão VPN para monitorar o tráfego da rede. Aceite apenas se você confiar na fonte. O ícone &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparecerá na tela quando a VPN estiver ativa."</string>
     <string name="legacy_title" msgid="192936250066580964">"O VPN está conectado"</string>
     <string name="session" msgid="6470628549473641030">"Sessão:"</string>
     <string name="duration" msgid="3584782459928719435">"Duração:"</string>
diff --git a/packages/VpnDialogs/res/values-pt-rPT/strings.xml b/packages/VpnDialogs/res/values-pt-rPT/strings.xml
index 01beddb..a310104 100644
--- a/packages/VpnDialogs/res/values-pt-rPT/strings.xml
+++ b/packages/VpnDialogs/res/values-pt-rPT/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Pedido de ligação"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> pretende configurar uma ligação VPN que lhe permita monitorizar o tráfego de rede. Aceite apenas se confiar na fonte. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece na parte superior do seu ecrã quando a VPN está ativa."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"A app <xliff:g id="APP">%s</xliff:g> pretende configurar uma ligação VPN que lhe permita monitorizar o tráfego de rede. Aceite apenas se confiar na origem. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece no ecrã quando a VPN está ativa."</string>
     <string name="legacy_title" msgid="192936250066580964">"A VPN está ligada"</string>
     <string name="session" msgid="6470628549473641030">"Sessão"</string>
     <string name="duration" msgid="3584782459928719435">"Duração:"</string>
@@ -25,12 +26,12 @@
     <string name="data_received" msgid="4062776929376067820">"Recebidos:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bytes / <xliff:g id="NUMBER_1">%2$s</xliff:g> pacotes"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"Não é possível estabelecer ligação à VPN sempre ativada"</string>
-    <string name="always_on_disconnected_message" msgid="555634519845992917">"A aplicação <xliff:g id="VPN_APP_0">%1$s</xliff:g> está configurada para se manter sempre ligada, mas, neste momento, não é possível estabelecer ligação. O seu telemóvel irá utilizar uma rede pública até conseguir restabelecer ligação à aplicação <xliff:g id="VPN_APP_1">%1$s</xliff:g>."</string>
-    <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"A aplicação <xliff:g id="VPN_APP">%1$s</xliff:g> está configurada para se manter sempre ligada, mas, neste momento, não é possível estabelecer ligação. Não terá ligação até que a VPN a consiga restabelecer."</string>
+    <string name="always_on_disconnected_message" msgid="555634519845992917">"A app <xliff:g id="VPN_APP_0">%1$s</xliff:g> está configurada para se manter sempre ligada, mas, neste momento, não é possível estabelecer ligação. O seu telemóvel irá utilizar uma rede pública até conseguir restabelecer ligação à app <xliff:g id="VPN_APP_1">%1$s</xliff:g>."</string>
+    <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"A app <xliff:g id="VPN_APP">%1$s</xliff:g> está configurada para se manter sempre ligada, mas, neste momento, não é possível estabelecer ligação. Não terá ligação até que a VPN a consiga restabelecer."</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Alterar as definições da VPN"</string>
     <string name="configure" msgid="4905518375574791375">"Configurar"</string>
     <string name="disconnect" msgid="971412338304200056">"Desligar"</string>
-    <string name="open_app" msgid="3717639178595958667">"Abrir aplicação"</string>
+    <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorar"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pt/strings.xml b/packages/VpnDialogs/res/values-pt/strings.xml
index 75c1406..0d6dd0b 100644
--- a/packages/VpnDialogs/res/values-pt/strings.xml
+++ b/packages/VpnDialogs/res/values-pt/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitação de conexão"</string>
     <string name="warning" msgid="809658604548412033">"O <xliff:g id="APP">%s</xliff:g> quer configurar uma conexão VPN que permite monitorar o tráfego da rede. Aceite somente se confiar na origem. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; é exibido na parte superior da tela quando a rede VPN estiver ativa."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"O app <xliff:g id="APP">%s</xliff:g> quer definir uma conexão VPN para monitorar o tráfego da rede. Aceite apenas se você confiar na fonte. O ícone &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparecerá na tela quando a VPN estiver ativa."</string>
     <string name="legacy_title" msgid="192936250066580964">"O VPN está conectado"</string>
     <string name="session" msgid="6470628549473641030">"Sessão:"</string>
     <string name="duration" msgid="3584782459928719435">"Duração:"</string>
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index 4e60df2..5bda87e 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitare de conexiune"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> dorește să configureze o conexiune VPN care să îi permită să monitorizeze traficul în rețea. Acceptați numai dacă aveți încredere în sursă. Atunci când conexiunea VPN este activă, &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se afișează în partea de sus a ecranului."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> solicită permisiunea de a configura o conexiune VPN care să îi permită să monitorizeze traficul de rețea. Acceptați numai dacă aveți încredere în sursă. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; va apărea pe ecran atunci când conexiunea VPN este activă."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN este conectat"</string>
     <string name="session" msgid="6470628549473641030">"Sesiune:"</string>
     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
diff --git a/packages/VpnDialogs/res/values-ru/strings.xml b/packages/VpnDialogs/res/values-ru/strings.xml
index f8fcfb8..ce099562 100644
--- a/packages/VpnDialogs/res/values-ru/strings.xml
+++ b/packages/VpnDialogs/res/values-ru/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Запрос на подключение"</string>
     <string name="warning" msgid="809658604548412033">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" пытается подключиться к сети VPN, чтобы отслеживать трафик. Этот запрос следует принимать, только если вы доверяете источнику. <br /><br />Когда подключение к сети VPN активно, в верхней части экрана появляется значок &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" пытается подключиться к сети VPN, чтобы отслеживать трафик. Этот запрос следует принимать, только если вы доверяете источнику. Когда подключение к сети VPN активно, на экране появляется значок &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN-подключение установлено"</string>
     <string name="session" msgid="6470628549473641030">"Сеанс:"</string>
     <string name="duration" msgid="3584782459928719435">"Продолжительность:"</string>
diff --git a/packages/VpnDialogs/res/values-si/strings.xml b/packages/VpnDialogs/res/values-si/strings.xml
index bb97a5d..a836bae 100644
--- a/packages/VpnDialogs/res/values-si/strings.xml
+++ b/packages/VpnDialogs/res/values-si/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"සම්බන්ධතා ඉල්ලීම"</string>
     <string name="warning" msgid="809658604548412033">"ජාල තදබදය නිරීක්ෂණය කිරීමට ඉඩ දෙන VPN සම්බන්ධතාවක් සැකසීමට <xliff:g id="APP">%s</xliff:g> අවශ්‍යය වේ. ප්‍රභවය ඔබ විශ්වාස කරන්නේ නම් පමණක් පිළිගන්න. VPN සක්‍රිය විට &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"ජාල තදබදය නිරීක්ෂණය කිරීමට ඉඩ දෙන VPN සම්බන්ධතාවක් සැකසීමට <xliff:g id="APP">%s</xliff:g> හට අවශ්‍ය වේ. ඔබ මූලාශ්‍රය විශ්වාස කරන්නේ නම් පමණක් පිළිගන්න. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN සක්‍රිය විට ඔබගේ තිරයෙහි දිස් වේ."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN සම්බන්ධිතයි"</string>
     <string name="session" msgid="6470628549473641030">"සැසිය:"</string>
     <string name="duration" msgid="3584782459928719435">"කාල සීමාව:"</string>
diff --git a/packages/VpnDialogs/res/values-sk/strings.xml b/packages/VpnDialogs/res/values-sk/strings.xml
index a08117a..766c139 100644
--- a/packages/VpnDialogs/res/values-sk/strings.xml
+++ b/packages/VpnDialogs/res/values-sk/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Žiadosť o pripojenie"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> žiada o nastavenie pripojenia VPN, pomocou ktorého bude môcť sledovať sieťové prenosy. Povoľte iba v prípade, že zdroju dôverujete. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; sa zobrazuje v hornej časti obrazovky, keď je pripojenie VPN aktívne."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikácia <xliff:g id="APP">%s</xliff:g> chce nastaviť pripojenie k sieti VPN, ktoré jej umožňuje sledovať sieťovú premávku. Povoľte to iba v prípade, ak zdroju dôverujete. &lt;br /&gt; &lt;br /&gt; Keď je sieť VPN aktívna, na obrazovke sa zobrazí ikona &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"Sieť VPN je pripojená"</string>
     <string name="session" msgid="6470628549473641030">"Relácia"</string>
     <string name="duration" msgid="3584782459928719435">"Trvanie:"</string>
diff --git a/packages/VpnDialogs/res/values-sl/strings.xml b/packages/VpnDialogs/res/values-sl/strings.xml
index d5014fa34..361a5fa 100644
--- a/packages/VpnDialogs/res/values-sl/strings.xml
+++ b/packages/VpnDialogs/res/values-sl/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Zahteva za povezavo"</string>
     <string name="warning" msgid="809658604548412033">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi nastaviti povezavo VPN, ki omogoča nadzor omrežnega prometa. To sprejmite samo, če zaupate viru. Ko je povezava VPN aktivna, se na vrhu zaslona prikaže ikona &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi nastaviti povezavo VPN, ki ji omogoča nadzor omrežnega prometa. To sprejmite samo, če zaupate viru. Ko je povezava VPN aktivna, je na zaslonu prikazana ikona &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"Povezava z navideznim zasebnim omrežjem je vzpostavljena"</string>
     <string name="session" msgid="6470628549473641030">"Seja:"</string>
     <string name="duration" msgid="3584782459928719435">"Trajanje:"</string>
diff --git a/packages/VpnDialogs/res/values-sq/strings.xml b/packages/VpnDialogs/res/values-sq/strings.xml
index 4a96e7b..0b4ce4df 100644
--- a/packages/VpnDialogs/res/values-sq/strings.xml
+++ b/packages/VpnDialogs/res/values-sq/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Kërkesë për lidhje"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> kërkon të vendosë një lidhje VPN-je që e lejon të monitorojë trafikun e rrjetit. Prano vetëm nëse i beson burimit. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; shfaqet në krye të ekranit kur VPN-ja është aktive."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> kërkon të vendosë një lidhje VPN që i lejon të monitorojë trafikun e rrjetit. Pranoje vetëm nëse i beson burimit. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; shfaqet në ekranin tënd kur është aktive VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN-ja është e lidhur"</string>
     <string name="session" msgid="6470628549473641030">"Sesioni:"</string>
     <string name="duration" msgid="3584782459928719435">"Kohëzgjatja:"</string>
diff --git a/packages/VpnDialogs/res/values-sr/strings.xml b/packages/VpnDialogs/res/values-sr/strings.xml
index 8ce8060..01bd4df 100644
--- a/packages/VpnDialogs/res/values-sr/strings.xml
+++ b/packages/VpnDialogs/res/values-sr/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Захтев за повезивање"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> жели да подеси VPN везу која омогућава праћење саобраћаја на мрежи. Прихватите само ако верујете извору. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; се приказује у врху екрана када је VPN активан."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Апликација <xliff:g id="APP">%s</xliff:g> жели да подеси VPN везу која јој омогућава да прати мрежни саобраћај. Прихватите ово само ако имате поверења у извор. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; се приказује на екрану када је VPN активан."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN је повезан"</string>
     <string name="session" msgid="6470628549473641030">"Сесија:"</string>
     <string name="duration" msgid="3584782459928719435">"Трајање:"</string>
diff --git a/packages/VpnDialogs/res/values-sv/strings.xml b/packages/VpnDialogs/res/values-sv/strings.xml
index 16b6a31..60ed752 100644
--- a/packages/VpnDialogs/res/values-sv/strings.xml
+++ b/packages/VpnDialogs/res/values-sv/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Anslutningsförfrågan"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vill starta en VPN-anslutning som tillåter att appen övervakar nätverkstrafiken. Godkänn endast detta om du litar på källan. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; visas längst upp på skärmen när VPN-anslutningen är aktiv."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> vill skapa en VPN-anslutning så att den kan övervaka nätverkstrafik. Godkänn bara om du litar på källan. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; visas på skärmen när VPN-anslutningen är aktiv."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN är anslutet"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Längd:"</string>
diff --git a/packages/VpnDialogs/res/values-sw/strings.xml b/packages/VpnDialogs/res/values-sw/strings.xml
index ea26884..c4f4662 100644
--- a/packages/VpnDialogs/res/values-sw/strings.xml
+++ b/packages/VpnDialogs/res/values-sw/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Ombi la muunganisho"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> inataka kusanidi muunganisho wa VPN utakaoiruhusu kufuatilia shughuli kwenye mtandao. Kubali ikiwa tu unakiamini chanzo. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; huonekana sehemu ya juu ya skrini yako VPN inapofanya kazi."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> inagependa kuweka mipangilio ya muunganisho wa VPN inayoiruhusu kufuatilia trafiki ya mtandao. Kubali tu iwapo unaamini chanzo. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; huonekana kwenye skrini yako VPN inapotumika."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN imeunganishwa"</string>
     <string name="session" msgid="6470628549473641030">"Kipindi:"</string>
     <string name="duration" msgid="3584782459928719435">"Muda:"</string>
diff --git a/packages/VpnDialogs/res/values-ta/strings.xml b/packages/VpnDialogs/res/values-ta/strings.xml
index 3b4cc57..1385bdc 100644
--- a/packages/VpnDialogs/res/values-ta/strings.xml
+++ b/packages/VpnDialogs/res/values-ta/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"இணைப்புக் கோரிக்கை"</string>
     <string name="warning" msgid="809658604548412033">"நெட்வொர்க் டிராஃபிக்கைக் கண்காணிக்க வசதியாக VPN இணைப்பை அமைக்க <xliff:g id="APP">%s</xliff:g> கோருகிறது. நம்பகமான மூலத்தை மட்டுமே ஏற்கவும். &lt;br /&gt; &lt;br /&gt; VPN இயக்கத்தில் உள்ளபோது திரையின் மேல் பகுதியில் &lt;img src=vpn_icon /&gt; தோன்றும்."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"நெட்வொர்க் டிராஃபிக்கைக் கண்காணிக்க அனுமதிக்கும் VPN இணைப்பை அமைக்க <xliff:g id="APP">%s</xliff:g> விரும்புகிறது. நம்பகமான VPN ஆப்ஸாக இருந்தால் மட்டுமே ஏற்கவும். &lt;br /&gt; &lt;br /&gt; VPN இயங்கும்போது உங்கள் திரையில் &lt;img src=vpn_icon /&gt; தோன்றும்."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN இணைக்கப்பட்டது"</string>
     <string name="session" msgid="6470628549473641030">"அமர்வு:"</string>
     <string name="duration" msgid="3584782459928719435">"காலஅளவு:"</string>
diff --git a/packages/VpnDialogs/res/values-te/strings.xml b/packages/VpnDialogs/res/values-te/strings.xml
index 864c926..2316c62 100644
--- a/packages/VpnDialogs/res/values-te/strings.xml
+++ b/packages/VpnDialogs/res/values-te/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"కనెక్షన్ అభ్యర్థన"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> నెట్‌వర్క్ ట్రాఫిక్‌ని పర్యవేక్షించగలగడానికి VPN కనెక్షన్‌ను సెటప్ చేయాలనుకుంటోంది. మీరు మూలాన్ని విశ్వసిస్తే మాత్రమే ఆమోదించండి. VPN సక్రియంగా ఉన్నప్పుడు మీ స్క్రీన్ ఎగువన &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; కనిపిస్తుంది."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"నెట్‌వర్క్ ట్రాఫిక్‌ను పర్యవేక్షించగలగడానికి, <xliff:g id="APP">%s</xliff:g> VPN కనెక్షన్‌ను సెటప్ చేయాలనుకుంటోంది. మీరు సోర్స్‌ను విశ్వసిస్తే మాత్రమే ఆమోదించండి. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; VPN యాక్టివ్‌గా ఉన్నప్పుడు మీ స్క్రీన్ పై కనిపిస్తుంది."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN కనెక్ట్ చేయబడింది"</string>
     <string name="session" msgid="6470628549473641030">"సెషన్:"</string>
     <string name="duration" msgid="3584782459928719435">"వ్యవధి:"</string>
diff --git a/packages/VpnDialogs/res/values-th/strings.xml b/packages/VpnDialogs/res/values-th/strings.xml
index 333ff5f..2e174cd 100644
--- a/packages/VpnDialogs/res/values-th/strings.xml
+++ b/packages/VpnDialogs/res/values-th/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"ขอการเชื่อมต่อ"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ต้องการสร้างการเชื่อมต่อ VPN เพื่อให้แอปสามารถตรวจสอบการเข้าใช้งานเครือข่าย โปรดยอมรับหากคุณเชื่อถือแหล่งที่มานี้เท่านั้น &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; จะปรากฏที่ด้านบนหน้าจอเมื่อมีการใช้งาน VPN อยู่"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ต้องการตั้งค่าการเชื่อมต่อ VPN เพื่อให้ตรวจสอบการจราจรของข้อมูลในเครือข่ายได้ ยอมรับต่อเมื่อคุณไว้วางใจแหล่งที่มานี้เท่านั้น &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; จะปรากฏบนหน้าจอเมื่อใช้งาน VPN อยู่"</string>
     <string name="legacy_title" msgid="192936250066580964">"เชื่อมต่อ VPN แล้ว"</string>
     <string name="session" msgid="6470628549473641030">"เซสชัน"</string>
     <string name="duration" msgid="3584782459928719435">"ระยะเวลา:"</string>
diff --git a/packages/VpnDialogs/res/values-tl/strings.xml b/packages/VpnDialogs/res/values-tl/strings.xml
index 9c01c32..ea69fba 100644
--- a/packages/VpnDialogs/res/values-tl/strings.xml
+++ b/packages/VpnDialogs/res/values-tl/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Kahilingan sa koneksyon"</string>
     <string name="warning" msgid="809658604548412033">"Gusto ng <xliff:g id="APP">%s</xliff:g> na mag-set up ng koneksyon sa VPN na nagbibigay-daan ditong masubaybayan ang trapiko ng network. Tanggapin lang kung pinagkakatiwalaan mo ang pinagmulan. Lalabas ang &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; sa itaas ng iyong screen kapag aktibo ang VPN."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"Gusto ng <xliff:g id="APP">%s</xliff:g> na mag-set up ng koneksyon sa VPN na nagbibigay-daan ditong masubaybayan ang trapiko sa network. Tanggapin lang kung pinagkakatiwalaan mo ang pinagmulan. Lalabas ang &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; sa iyong screen kapag aktibo ang VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"Nakakonekta ang VPN"</string>
     <string name="session" msgid="6470628549473641030">"Session:"</string>
     <string name="duration" msgid="3584782459928719435">"Tagal:"</string>
diff --git a/packages/VpnDialogs/res/values-tr/strings.xml b/packages/VpnDialogs/res/values-tr/strings.xml
index 8665a47..7ffa4bc 100644
--- a/packages/VpnDialogs/res/values-tr/strings.xml
+++ b/packages/VpnDialogs/res/values-tr/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Bağlantı isteği"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ağ trafiğini izlemesine olanak veren bir VPN bağlantısı oluşturmak istiyor. Sadece, ilgili kaynağa güveniyorsanız kabul edin. &lt;br /&gt; &lt;br /&gt; VPN aktif olduğunda ekranınızın üst tarafında &lt;img src=vpn_icon /&gt; simgesi görünür."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>, ağ trafiğini izlemesine izin veren bir VPN bağlantısı oluşturmak istiyor. Yalnızca kaynağa güveniyorsanız kabul edin. VPN etkin olduğunda ekranınızda &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; görünür."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN bağlı"</string>
     <string name="session" msgid="6470628549473641030">"Oturum:"</string>
     <string name="duration" msgid="3584782459928719435">"Süre:"</string>
diff --git a/packages/VpnDialogs/res/values-uk/strings.xml b/packages/VpnDialogs/res/values-uk/strings.xml
index 8f91abf..6411d7c 100644
--- a/packages/VpnDialogs/res/values-uk/strings.xml
+++ b/packages/VpnDialogs/res/values-uk/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Запит на під’єднання"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> хоче під’єднатися до мережі VPN, щоб контролювати мережевий трафік. Дозволяйте, якщо довіряєте джерелу. Коли мережа VPN активна, угорі екрана відображається значок &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> хоче під’єднатися до мережі VPN, щоб контролювати мережевий трафік. Надавайте дозвіл, лише якщо довіряєте джерелу. Коли мережа VPN активна, на екрані з’являється значок &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;."</string>
     <string name="legacy_title" msgid="192936250066580964">"Мережу VPN під’єднано"</string>
     <string name="session" msgid="6470628549473641030">"Сеанс:"</string>
     <string name="duration" msgid="3584782459928719435">"Тривалість:"</string>
diff --git a/packages/VpnDialogs/res/values-ur/strings.xml b/packages/VpnDialogs/res/values-ur/strings.xml
index db0c297..3a23e94 100644
--- a/packages/VpnDialogs/res/values-ur/strings.xml
+++ b/packages/VpnDialogs/res/values-ur/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"کنکشن کی درخواست"</string>
     <string name="warning" msgid="809658604548412033">"‏<xliff:g id="APP">%s</xliff:g> ایک ایسا VPN کنکشن ترتیب دینا چاہتی ہے جو اسے نیٹ ورک ٹریفک کو مانیٹر کرنے کی اجازت دیتا ہے۔ اگر آپ کو ماخذ پر بھروسہ ہے تبھی قبول کریں۔ &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; آپ کی اسکرین کے اوپر اس وقت ظاہر ہوتا ہے جب VPN فعال ہوتا ہے۔"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"‏<xliff:g id="APP">%s</xliff:g> ایک ایسا VPN کنکشن سیٹ اپ کرنا چاہتی ہے جو اسے نیٹ ورک ٹریفک کو مانیٹر کرنے کی اجازت دیتا ہو۔ آپ کو ماخذ پر اعتماد ہونے پر ہی قبول کریں۔ ‎&lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ‏VPN کے فعال ہونے پر آپ کی اسکرین پر ظاہر ہوتا ہے۔"</string>
     <string name="legacy_title" msgid="192936250066580964">"‏VPN مربوط ہے"</string>
     <string name="session" msgid="6470628549473641030">"سیشن:"</string>
     <string name="duration" msgid="3584782459928719435">"دورانیہ:"</string>
diff --git a/packages/VpnDialogs/res/values-uz/strings.xml b/packages/VpnDialogs/res/values-uz/strings.xml
index 5a348a0..a3256e7 100644
--- a/packages/VpnDialogs/res/values-uz/strings.xml
+++ b/packages/VpnDialogs/res/values-uz/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Ulanish uchun so‘rov"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ilovasi trafikni kuzatish uchun VPN tarmog‘iga ulanmoqchi. Agar ilovaga ishonsangiz, so‘rovga rozi bo‘ling.&lt;br /&gt; &lt;br /&gt;VPN faol bo‘lsa, ekranning yuqori qismida &lt;img src=vpn_icon /&gt; belgisi paydo bo‘ladi."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ilovasi tarmoqdagi trafikni kuzatish uchun VPN aloqasini sozlamoqchi. Agar unga ishonsangiz, ruxsat bering. VPN aloqa faolligida ekranda &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; chiqadi."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ulangan"</string>
     <string name="session" msgid="6470628549473641030">"Seans:"</string>
     <string name="duration" msgid="3584782459928719435">"Davomiyligi:"</string>
diff --git a/packages/VpnDialogs/res/values-vi/strings.xml b/packages/VpnDialogs/res/values-vi/strings.xml
index 097c9ae..184d08d 100644
--- a/packages/VpnDialogs/res/values-vi/strings.xml
+++ b/packages/VpnDialogs/res/values-vi/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Yêu cầu kết nối"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> muốn thiết lập kết nối VPN cho phép ứng dụng giám sát lưu lượng truy cập mạng. Chỉ chấp nhận nếu bạn tin tưởng nguồn. &lt;br /&gt; &lt;br /&gt; Biểu tượng &lt;img src=vpn_icon /&gt; xuất hiện ở đầu màn hình của bạn khi VPN đang hoạt động."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> muốn thiết lập kết nối VPN cho phép ứng dụng giám sát lưu lượng truy cập mạng. Bạn chỉ nên chấp nhận nếu tin tưởng nguồn đó. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; sẽ xuất hiện trên màn hình khi VPN đang hoạt động."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN được kết nối"</string>
     <string name="session" msgid="6470628549473641030">"Phiên"</string>
     <string name="duration" msgid="3584782459928719435">"Thời lượng:"</string>
diff --git a/packages/VpnDialogs/res/values-zh-rCN/strings.xml b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
index 7e528bd..a7262be 100644
--- a/packages/VpnDialogs/res/values-zh-rCN/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"网络连接请求"</string>
     <string name="warning" msgid="809658604548412033">"“<xliff:g id="APP">%s</xliff:g>”想要设置一个 VPN 连接,以便监控网络流量。除非您信任该来源,否则请勿接受此请求。&lt;br /&gt; &lt;br /&gt;启用 VPN 后,屏幕顶部会出现一个 &lt;img src=vpn_icon /&gt; 图标。"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"“<xliff:g id="APP">%s</xliff:g>”想要建立一个 VPN 连接,以便监控网络流量。除非您信任该来源,否则请不要接受。VPN 处于启用状态时,屏幕上会显示 &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;。"</string>
     <string name="legacy_title" msgid="192936250066580964">"已连接VPN"</string>
     <string name="session" msgid="6470628549473641030">"会话:"</string>
     <string name="duration" msgid="3584782459928719435">"时长:"</string>
diff --git a/packages/VpnDialogs/res/values-zh-rHK/strings.xml b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
index 49605b0..e4e6432 100644
--- a/packages/VpnDialogs/res/values-zh-rHK/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"連線要求"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> 要求設定 VPN 連線以監控網絡流量。除非您信任要求來源,否則請勿隨意接受要求。&lt;br /&gt; &lt;br /&gt;VPN 啟用時,畫面頂端會顯示 &lt;img src=vpn_icon /&gt;。"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"「<xliff:g id="APP">%s</xliff:g>」要求設定 VPN 連線以監控網絡流量。除非您信任要求來源,否則請勿隨意接受要求。VPN 啟用時,畫面會顯示 &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt;。"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN 已連線"</string>
     <string name="session" msgid="6470628549473641030">"時段:"</string>
     <string name="duration" msgid="3584782459928719435">"持續時間︰"</string>
diff --git a/packages/VpnDialogs/res/values-zh-rTW/strings.xml b/packages/VpnDialogs/res/values-zh-rTW/strings.xml
index edd8e61..f54ca4a 100644
--- a/packages/VpnDialogs/res/values-zh-rTW/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rTW/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"連線要求"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> 要求設定 VPN 連線,允許此要求即開放該來源監控網路流量。除非你信任該來源,否則請勿任意接受要求。&lt;br /&gt; &lt;br /&gt;VPN 啟用時,畫面頂端會顯示 &lt;img src=vpn_icon /&gt;。"</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"「<xliff:g id="APP">%s</xliff:g>」要求設定 VPN 連線,以便監控網路流量。除非你信任該來源,否則請勿接受要求。&lt;br /&gt; &lt;br /&gt; VPN 啟用時,畫面上會顯示 &lt;img src=vpn_icon /&gt;。"</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN 已連線"</string>
     <string name="session" msgid="6470628549473641030">"工作階段:"</string>
     <string name="duration" msgid="3584782459928719435">"持續時間:"</string>
diff --git a/packages/VpnDialogs/res/values-zu/strings.xml b/packages/VpnDialogs/res/values-zu/strings.xml
index 4ab1225..c224b13 100644
--- a/packages/VpnDialogs/res/values-zu/strings.xml
+++ b/packages/VpnDialogs/res/values-zu/strings.xml
@@ -18,6 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Isicelo soxhumo"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ifuna ukusetha uxhumo lwe-VPN eyivumela ukwengamela ithrafikhi yenethiwekhi. Yamukela kuphela uma wethemba umthombo. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ibonakala phezu kwesikrini sakho uma i-VPN isebenza."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"I-<xliff:g id="APP">%s</xliff:g> ifuna ukusetha uxhumano lwe-VPN oluyivumela ukuthi igade ithrafikhi yenethiwekhi. Yamukela kuphela uma wethemba umthombo. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; ivela kusikrini sakho lapho i-VPN isebenza."</string>
     <string name="legacy_title" msgid="192936250066580964">"I-VPN ixhunyiwe"</string>
     <string name="session" msgid="6470628549473641030">"Iseshini:"</string>
     <string name="duration" msgid="3584782459928719435">"Ubude besikhathi:"</string>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml
new file mode 100644
index 0000000..adc3086
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Lewer programme onder uitsnede-area"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml
new file mode 100644
index 0000000..648e1d4
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ከተቆረጠው አከባቢ በታች የመተግበሪያዎች ምስልን ስራ"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml
new file mode 100644
index 0000000..2d3b506
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"عرض التطبيقات أسفل منطقة الصورة المقطوعة للشاشة"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml
new file mode 100644
index 0000000..db2b15a
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"এপ্‌সমূহ কাটআউট অঞ্চলৰ তলত দেখুৱাওক"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml
new file mode 100644
index 0000000..a6b7c43
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Tətbiqləri kəsilmə sahəsinin aşağısında göstərin"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..f80fa8d
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Prikazuj aplikacije ispod oblasti izreza"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml
new file mode 100644
index 0000000..0e5c8bc
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Візуалізацыя праграм ніжэй месца выраза"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml
new file mode 100644
index 0000000..e97bb57
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Изобразяване на приложенията под областта на прореза"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..d13c777
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"কাটআউট এরিয়ার নিচে অ্যাপ রেন্ডার করুন"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml
new file mode 100644
index 0000000..9c9f437
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderovanje aplikacija ispod izrezanog područja"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml
new file mode 100644
index 0000000..e0a577e
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderitza les aplicacions per sota de l\'àrea de retallada"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml
new file mode 100644
index 0000000..0f64473
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Vykreslovat aplikace pod oblastí výseče"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml
new file mode 100644
index 0000000..d0cc43e
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Gengiv apps under skærmhakkets område"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml
new file mode 100644
index 0000000..a7759ea
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Apps unterhalb des Aussparungs-Bereichs darstellen"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml
new file mode 100644
index 0000000..b71679a
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Απόδοση εφαρμογών κάτω από την περιοχή εγκοπής"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..8c85cbd
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..8c85cbd
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..8c85cbd
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..8c85cbd
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render apps below cutout area"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..8b72d9f
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎Render apps below cutout area‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..359cdd0
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps debajo del área de recorte"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml
new file mode 100644
index 0000000..47f525e
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar aplicaciones por debajo de la zona de recorte"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml
new file mode 100644
index 0000000..0cc5a25
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Väljalõikeala all olevate rakenduste renderdamine"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml
new file mode 100644
index 0000000..15d7d60
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Errendatu mozketa-eremutik kanpo geratzen diren aplikazioak"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml
new file mode 100644
index 0000000..0865f75
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"پرداز زدن برنامه‌ها در زیر ناحیه بریده‌شده"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml
new file mode 100644
index 0000000..1a6bf7a
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderöi sovellukset lovialueen alle"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..ea0a27b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Rendre les applications sous la zone de découpe"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml
new file mode 100644
index 0000000..6d91a9d
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Afficher les applis sous la zone d\'encoche"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml
new file mode 100644
index 0000000..382497b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar aplicacións que aparezan na zona recortada"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..d578d92
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ઍપને કટઆઉટ ક્ષેત્રની નીચે રેન્ડર કરો"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml
new file mode 100644
index 0000000..e1f09f2
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ऐप्लिकेशन को कटआउट एरिया के नीचे दिखाएं"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml
new file mode 100644
index 0000000..db734e8
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderiraj aplikacije ispod područja ureza"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml
new file mode 100644
index 0000000..264095b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Alkalmazások megjelenítése a kivágási terület alatt"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml
new file mode 100644
index 0000000..72e67ec
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Արտապատկերել հավելվածները էկրանի կտրված հատվածի ներքևում"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml
new file mode 100644
index 0000000..c49bf0c
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Render aplikasi di bawah area potongan"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml
new file mode 100644
index 0000000..0b90991
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Birta forrit fyrir neðan útklippta svæðið"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml
new file mode 100644
index 0000000..2a0f026b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Visualizza le app sotto l\'area di ritaglio"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..cc7a0a4
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"עיבוד האפליקציות שמתחת לאזור המגרעת"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml
new file mode 100644
index 0000000..9e99482
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"カットアウト領域の下でアプリをレンダリング"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml
new file mode 100644
index 0000000..5464a56
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"აპების ასახვა ჭრილის ქვემოთ"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml
new file mode 100644
index 0000000..6a2623f
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Экран ойығының астындағы қолданбаларды көрсету"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml
new file mode 100644
index 0000000..4b4d169
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"បំប្លែងកម្មវិធីខាងក្រោមផ្នែកឆក"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml
new file mode 100644
index 0000000..7a929d1
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ಕಟೌಟ್ ಪ್ರದೇಶದ ಕೆಳಗಿನ ಆ್ಯಪ್‌ಗಳನ್ನು ರೆಂಡರ್ ಮಾಡಿ"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml
new file mode 100644
index 0000000..4b9e640
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"컷아웃 영역 아래에 앱 렌더링"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml
new file mode 100644
index 0000000..1ac6a8b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Колдонмолорду кесилген аймактын ылдый жагында көрсөтүү"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml
new file mode 100644
index 0000000..4c38580
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ສະແດງພາບແອັບຢູ່ທາງລຸ່ມພື້ນທີ່ຮອຍເສັ້ນ"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml
new file mode 100644
index 0000000..c43736d
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Pateikti programas po išpjovos sritimi"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml
new file mode 100644
index 0000000..f95abb6
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Atveidot lietotnes zem izgriezuma apgabala"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml
new file mode 100644
index 0000000..ff236be
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Прикажувај апликации под отсечената област"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml
new file mode 100644
index 0000000..ef728ab
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"കട്ടൗട്ട് ഭാഗത്തിന് താഴെ ആപ്പുകൾ റെൻഡർ ചെയ്യുക"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml
new file mode 100644
index 0000000..23dbe0c
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Аппуудыг тасалж авсан хэсгийн доор буулгах"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..42f09cb
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"कटआउट क्षेत्राच्या खाली असलेली ॲप्स रेंडर करा"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml
new file mode 100644
index 0000000..e348630
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Serahkan apl di bawah kawasan potongan"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml
new file mode 100644
index 0000000..90cb0a5
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ဖြတ်ထုတ်ထားသော နေရာအောက်ရှိ အက်ပ်များ ပြသရန်"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml
new file mode 100644
index 0000000..b8b4e75
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Gjengi apper under utklippsområdet"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..bd213bb
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"कटआउट गरिएको क्षेत्रभन्दा तल पर्ने एपहरू रेन्डर गर्नुहोस्"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml
new file mode 100644
index 0000000..68f5c07
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Apps renderen onder display-cutout"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml
new file mode 100644
index 0000000..162a29e
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ଆପଗୁଡ଼ିକୁ କଟଆଉଟ୍ ଏରିଆ ନିମ୍ନରେ ରେଣ୍ଡର୍ କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml
new file mode 100644
index 0000000..908393b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"ਕੱਟਆਊਟ ਖੇਤਰ ਹੇਠ ਐਪਾਂ ਨੂੰ ਰੈਂਡਰ ਕਰੋ"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml
new file mode 100644
index 0000000..c027d52
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderuj aplikacje pod obszarem wycięcia"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..d09ed97
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps abaixo da área de corte"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..d38ce43
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps abaixo da área de recorte"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml
new file mode 100644
index 0000000..d09ed97
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Renderizar apps abaixo da área de corte"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
new file mode 100644
index 0000000..6e5947c
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Redați aplicațiile sub zona de decupaj"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml
new file mode 100644
index 0000000..c7f54bb
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Отображать приложения под вырезом"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml
new file mode 100644
index 0000000..4a14a36
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"කටවුට් ප්‍රදේශයට පහළින් යෙදුම් විදහන්න"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml
new file mode 100644
index 0000000..98b82e6
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Vykresľovať aplikácie pod oblasťou výrezu"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml
new file mode 100644
index 0000000..dcf0c84
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Upodobitev aplikacij pod predelom zareze zaslona"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml
new file mode 100644
index 0000000..d7b0676
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Paraqiti aplikacionet poshtë zonës së prerjes"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml
new file mode 100644
index 0000000..c2b611e
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Приказуј апликације испод области изреза"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml
new file mode 100644
index 0000000..3007ffb
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Visa appar under skärmutskärningens område"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml
new file mode 100644
index 0000000..b605554
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Usionyeshe programu chini ya eneo lenye pengo"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..c4d06fb
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"கட் அவுட் பகுதிக்குள்ளாக ஆப்ஸை ரெண்டர் செய்"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml
new file mode 100644
index 0000000..08fa4ae
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"కట్అవుట్ ఏరియా కింద యాప్‌లను రెండర్ చేయండి"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml
new file mode 100644
index 0000000..9a30250
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"แสดงผลแอปใต้บริเวณรอยบาก"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml
new file mode 100644
index 0000000..a3d4a3a
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"I-render ang mga app sa ibaba ng lugar ng cutout"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml
new file mode 100644
index 0000000..12e0f30
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Uygulamaları kesme alanının altında oluşturun"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml
new file mode 100644
index 0000000..08b1521
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Відображати додатки під областю вирізу екрана"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..711b538
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"کٹ آؤٹ ایریا کے نیچے رینڈر ایپس"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml
new file mode 100644
index 0000000..7f6f2b4
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Ekran kesimi quyidagi ilovalarni renderlash"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml
new file mode 100644
index 0000000..a7d54fb
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Hiển thị các ứng dụng bên dưới khu vực có vết cắt"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..f596520
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"在刘海区域下方呈现应用"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..ddb1df7
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"在凹口區域下方輸出應用程式"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..7aad79c
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"在螢幕凹口底下顯示應用程式畫面"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml
new file mode 100644
index 0000000..d861c5e
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="3814493834951357513">"Nikezela ngama-app angaphansi kwendawo yokukhipha"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-af/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-af/strings.xml
new file mode 100644
index 0000000..b021da7
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Versteek"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-am/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-am/strings.xml
new file mode 100644
index 0000000..0ca6135
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ደብቅ"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ar/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ar/strings.xml
new file mode 100644
index 0000000..7e41cb1
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"إخفاء"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-as/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-as/strings.xml
new file mode 100644
index 0000000..d2399ff
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"লুকুৱাওক"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-az/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-az/strings.xml
new file mode 100644
index 0000000..420c513
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Gizlədin"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..082e586
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Sakrij"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-be/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-be/strings.xml
new file mode 100644
index 0000000..ce75c45
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Схаваць"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-bg/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-bg/strings.xml
new file mode 100644
index 0000000..7c3170c
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Скриване"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..1e62725
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"লুকান"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-bs/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-bs/strings.xml
new file mode 100644
index 0000000..082e586
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Sakrij"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ca/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ca/strings.xml
new file mode 100644
index 0000000..6ae5ffd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Amaga"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-cs/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-cs/strings.xml
new file mode 100644
index 0000000..068bb94
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Skrýt"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-da/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-da/strings.xml
new file mode 100644
index 0000000..6ecb767
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Skjul"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-de/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-de/strings.xml
new file mode 100644
index 0000000..44278e8
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ausblenden"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-el/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-el/strings.xml
new file mode 100644
index 0000000..96b1b86
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Απόκρυψη"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-en-rAU/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..1ab9b2d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Hide"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-en-rCA/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..1ab9b2d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Hide"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-en-rGB/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..1ab9b2d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Hide"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-en-rIN/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..1ab9b2d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Hide"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-en-rXC/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..a20e594
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎Hide‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-es-rUS/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..351c1cd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ocultar"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-es/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-es/strings.xml
new file mode 100644
index 0000000..351c1cd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ocultar"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-et/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-et/strings.xml
new file mode 100644
index 0000000..4e5428d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Peida"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-eu/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-eu/strings.xml
new file mode 100644
index 0000000..f33bb50
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ezkutatu"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-fa/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-fa/strings.xml
new file mode 100644
index 0000000..8de7560
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"پنهان کردن"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-fi/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-fi/strings.xml
new file mode 100644
index 0000000..c42e52d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Piilota"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..31fa567
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Masquer"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-fr/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-fr/strings.xml
new file mode 100644
index 0000000..31fa567
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Masquer"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-gl/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-gl/strings.xml
new file mode 100644
index 0000000..351c1cd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ocultar"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..7e4b33a
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"છુપાવો"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-hi/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-hi/strings.xml
new file mode 100644
index 0000000..1513f2a
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"छिपाएं"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-hr/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-hr/strings.xml
new file mode 100644
index 0000000..082e586
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Sakrij"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-hu/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-hu/strings.xml
new file mode 100644
index 0000000..2b9717f
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Elrejtés"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-hy/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-hy/strings.xml
new file mode 100644
index 0000000..3407bb4
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Թաքցնել"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-in/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-in/strings.xml
new file mode 100644
index 0000000..6c017b3
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Sembunyikan"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-is/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-is/strings.xml
new file mode 100644
index 0000000..229c113
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Fela"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-it/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-it/strings.xml
new file mode 100644
index 0000000..07444aa
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Nascondi"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-iw/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..221a129
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"הסתרה"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ja/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ja/strings.xml
new file mode 100644
index 0000000..3bf17fb
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"非表示"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ka/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ka/strings.xml
new file mode 100644
index 0000000..1600528
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"დამალვა"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-kk/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-kk/strings.xml
new file mode 100644
index 0000000..23d02b8
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Жасыру"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-km/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-km/strings.xml
new file mode 100644
index 0000000..624b81f
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"លាក់"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-kn/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-kn/strings.xml
new file mode 100644
index 0000000..9cd6da7
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ಮರೆಮಾಡಿ"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ko/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ko/strings.xml
new file mode 100644
index 0000000..efb6568
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"숨기기"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ky/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ky/strings.xml
new file mode 100644
index 0000000..4191325
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Жашыруу"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-lo/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-lo/strings.xml
new file mode 100644
index 0000000..8850dfb
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ເຊື່ອງ"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-lt/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-lt/strings.xml
new file mode 100644
index 0000000..6364b96
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Slėpti"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-lv/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-lv/strings.xml
new file mode 100644
index 0000000..61f2ad3
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Paslēpt"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-mk/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-mk/strings.xml
new file mode 100644
index 0000000..505c205
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Сокриј"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ml/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ml/strings.xml
new file mode 100644
index 0000000..1c30dec
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"മറയ്ക്കുക"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-mn/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-mn/strings.xml
new file mode 100644
index 0000000..7e2719b
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Нуух"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..46f0ab8
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"लपवा"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ms/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ms/strings.xml
new file mode 100644
index 0000000..6c017b3
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Sembunyikan"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-my/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-my/strings.xml
new file mode 100644
index 0000000..84be3f9
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ဝှက်ရန်"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-nb/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-nb/strings.xml
new file mode 100644
index 0000000..6ecb767
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Skjul"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..ff920b2
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"लुकाइयोस्"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-nl/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-nl/strings.xml
new file mode 100644
index 0000000..00900f8
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Verbergen"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-or/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-or/strings.xml
new file mode 100644
index 0000000..fcfd725
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ଲୁଚାନ୍ତୁ"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-pa/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-pa/strings.xml
new file mode 100644
index 0000000..9f37e0b
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ਲੁਕਾਓ"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-pl/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-pl/strings.xml
new file mode 100644
index 0000000..3d65546
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ukryj"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-pt-rBR/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..351c1cd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ocultar"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-pt-rPT/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..351c1cd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ocultar"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-pt/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-pt/strings.xml
new file mode 100644
index 0000000..351c1cd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ocultar"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ro/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ro/strings.xml
new file mode 100644
index 0000000..e6281fd
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ascundeți"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ru/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ru/strings.xml
new file mode 100644
index 0000000..9018396
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Скрыть"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-si/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-si/strings.xml
new file mode 100644
index 0000000..b06a52c
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"සඟවන්න"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-sk/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-sk/strings.xml
new file mode 100644
index 0000000..965d95b
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Skryť"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-sl/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-sl/strings.xml
new file mode 100644
index 0000000..e8adb98
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Skrij"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-sq/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-sq/strings.xml
new file mode 100644
index 0000000..85fb95a
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Fshih"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-sr/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-sr/strings.xml
new file mode 100644
index 0000000..26afbf9
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Сакриј"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-sv/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-sv/strings.xml
new file mode 100644
index 0000000..193c179
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Dölj"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-sw/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-sw/strings.xml
new file mode 100644
index 0000000..58e35e2
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ficha"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ta/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..b743c66
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"மறை"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-te/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-te/strings.xml
new file mode 100644
index 0000000..de04152
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"దాచండి"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-th/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-th/strings.xml
new file mode 100644
index 0000000..1c8bd9d
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"ซ่อน"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-tl/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-tl/strings.xml
new file mode 100644
index 0000000..cc45f63
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Itago"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-tr/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-tr/strings.xml
new file mode 100644
index 0000000..b20f1f7
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Gizle"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-uk/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-uk/strings.xml
new file mode 100644
index 0000000..938b0e2
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Сховати"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..0f08170
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"چھپائیں"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-uz/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-uz/strings.xml
new file mode 100644
index 0000000..5d22045
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Berkitish"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-vi/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-vi/strings.xml
new file mode 100644
index 0000000..fc83d25
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Ẩn"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-zh-rCN/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..acdfd1c
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"隐藏"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-zh-rHK/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..abb8e81
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"隱藏"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-zh-rTW/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..abb8e81
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"隱藏"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-zu/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-zu/strings.xml
new file mode 100644
index 0000000..11842d9
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"Fihla"</string>
+</resources>
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlend.java b/rs/java/android/renderscript/ScriptIntrinsicBlend.java
index a1c79ef..3109cd8 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlend.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlend.java
@@ -104,7 +104,7 @@
      * @param opt LaunchOptions for clipping
      */
     public void forEachSrc(Allocation ain, Allocation aout, Script.LaunchOptions opt) {
-        blend(1, ain, aout, null);
+        blend(1, ain, aout, opt);
     }
 
     /**
@@ -641,4 +641,3 @@
     }
 */
 }
-
diff --git a/services/Android.bp b/services/Android.bp
index c83a697..a2d6beb4 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -21,6 +21,9 @@
             // "-XepPatchLocation:/tmp/refaster/",
         ],
     },
+    lint: {
+        extra_check_modules: ["AndroidFrameworkLintChecker"],
+    },
 }
 
 filegroup {
@@ -130,6 +133,7 @@
     libs: [
         "android.hidl.manager-V1.0-java",
         "framework-tethering.stubs.module_lib",
+        "service-art.stubs.system_server",
     ],
 
     // Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/OWNERS b/services/OWNERS
index 3b972e9..b7128a3 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,6 +1,6 @@
 per-file Android.bp = file:platform/build/soong:/OWNERS
 
 # art-team@ manages the system server profile
-per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.com
 
 per-file java/com/android/server/* = toddke@google.com,patb@google.com
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index e9c9899..eec875a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -21,8 +21,13 @@
 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_STATUS;
 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP;
 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.accessibility.AccessibilityInteractionClient.CALL_STACK;
+import static android.view.accessibility.AccessibilityInteractionClient.IGNORE_CALL_STACK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
@@ -31,6 +36,7 @@
 import android.accessibilityservice.AccessibilityGestureEvent;
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
@@ -103,10 +109,9 @@
         FingerprintGestureDispatcher.FingerprintGestureClient {
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "AbstractAccessibilityServiceConnection";
-    private static final String TRACE_A11Y_SERVICE_CONNECTION =
-            LOG_TAG + ".IAccessibilityServiceConnection";
-    private static final String TRACE_A11Y_SERVICE_CLIENT =
-            LOG_TAG + ".IAccessibilityServiceClient";
+    private static final String TRACE_SVC_CONN = LOG_TAG + ".IAccessibilityServiceConnection";
+    private static final String TRACE_SVC_CLIENT = LOG_TAG + ".IAccessibilityServiceClient";
+    private static final String TRACE_WM = "WindowManagerInternal";
     private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
 
     protected static final String TAKE_SCREENSHOT = "takeScreenshot";
@@ -134,6 +139,9 @@
     protected final AccessibilitySecurityPolicy mSecurityPolicy;
     protected final AccessibilityTrace mTrace;
 
+    // The attribution tag set by the service that is bound to this instance
+    protected String mAttributionTag;
+
     // The service that's bound to this instance. Whenever this value is non-null, this
     // object is registered as a death recipient
     IBinder mService;
@@ -298,9 +306,8 @@
             return false;
         }
         try {
-            if (mTrace.isA11yTracingEnabled()) {
-                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onKeyEvent",
-                        keyEvent + ", " + sequenceNumber);
+            if (svcClientTracingEnabled()) {
+                logTraceSvcClient("onKeyEvent", keyEvent + ", " + sequenceNumber);
             }
             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
         } catch (RemoteException e) {
@@ -365,17 +372,16 @@
 
     @Override
     public void setOnKeyEventResult(boolean handled, int sequence) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setOnKeyEventResult",
-                    "handled=" + handled + ";sequence=" + sequence);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setOnKeyEventResult", "handled=" + handled + ";sequence=" + sequence);
         }
         mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
     }
 
     @Override
     public AccessibilityServiceInfo getServiceInfo() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getServiceInfo");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getServiceInfo", "");
         }
         synchronized (mLock) {
             return mAccessibilityServiceInfo;
@@ -393,8 +399,8 @@
 
     @Override
     public void setServiceInfo(AccessibilityServiceInfo info) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setServiceInfo", "info=" + info);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setServiceInfo", "info=" + info);
         }
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -416,13 +422,22 @@
         }
     }
 
+    @Override
+    public void setAttributionTag(String attributionTag) {
+        mAttributionTag = attributionTag;
+    }
+
+    String getAttributionTag() {
+        return mAttributionTag;
+    }
+
     protected abstract boolean hasRightsToCurrentUserLocked();
 
     @Nullable
     @Override
     public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindows");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getWindows", "");
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -458,8 +473,8 @@
 
     @Override
     public AccessibilityWindowInfo getWindow(int windowId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindow", "windowId=" + windowId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getWindow", "windowId=" + windowId);
         }
         synchronized (mLock) {
             int displayId = Display.INVALID_DISPLAY;
@@ -496,8 +511,8 @@
             long accessibilityNodeId, String viewIdResName, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByViewId",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("findAccessibilityNodeInfosByViewId",
                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
                     + accessibilityNodeId + ";viewIdResName=" + viewIdResName + ";interactionId="
                     + interactionId + ";callback=" + callback + ";interrogatingTid="
@@ -539,6 +554,12 @@
         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
         final long identityToken = Binder.clearCallingIdentity();
+        if (intConnTracingEnabled()) {
+            logTraceIntConn("findAccessibilityNodeInfosByViewId",
+                    accessibilityNodeId + ";" + viewIdResName + ";" + partialInteractiveRegion + ";"
+                    + interactionId + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid
+                    + ";" + interrogatingTid + ";" + spec);
+        }
         try {
             connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
                     viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
@@ -564,8 +585,8 @@
             long accessibilityNodeId, String text, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByText",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("findAccessibilityNodeInfosByText",
                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
                     + accessibilityNodeId + ";text=" + text + ";interactionId=" + interactionId
                     + ";callback=" + callback + ";interrogatingTid=" + interrogatingTid);
@@ -606,6 +627,12 @@
         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
         final long identityToken = Binder.clearCallingIdentity();
+        if (intConnTracingEnabled()) {
+            logTraceIntConn("findAccessibilityNodeInfosByText",
+                    accessibilityNodeId + ";" + text + ";" + partialInteractiveRegion + ";"
+                    + interactionId + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid
+                    + ";" + interrogatingTid + ";" + spec);
+        }
         try {
             connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
                     text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
@@ -631,13 +658,12 @@
             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             long interrogatingTid, Bundle arguments) throws RemoteException {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(
-                    TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfoByAccessibilityId",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("findAccessibilityNodeInfoByAccessibilityId",
                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
-                            + accessibilityNodeId + ";interactionId=" + interactionId + ";callback="
-                            + callback + ";flags=" + flags + ";interrogatingTid=" + interrogatingTid
-                            + ";arguments=" + arguments);
+                    + accessibilityNodeId + ";interactionId=" + interactionId + ";callback="
+                    + callback + ";flags=" + flags + ";interrogatingTid=" + interrogatingTid
+                    + ";arguments=" + arguments);
         }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
@@ -675,6 +701,12 @@
         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
         final long identityToken = Binder.clearCallingIdentity();
+        if (intConnTracingEnabled()) {
+            logTraceIntConn("findAccessibilityNodeInfoByAccessibilityId",
+                    accessibilityNodeId + ";" + partialInteractiveRegion + ";" + interactionId + ";"
+                    + callback + ";" + (mFetchFlags | flags) + ";" + interrogatingPid + ";"
+                    + interrogatingTid + ";" + spec + ";" + arguments);
+        }
         try {
             connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
                     accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
@@ -700,12 +732,12 @@
             int focusType, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findFocus",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("findFocus",
                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
-                            + accessibilityNodeId + ";focusType=" + focusType + ";interactionId="
-                            + interactionId + ";callback=" + callback + ";interrogatingTid="
-                            + interrogatingTid);
+                    + accessibilityNodeId + ";focusType=" + focusType + ";interactionId="
+                    + interactionId + ";callback=" + callback + ";interrogatingTid="
+                    + interrogatingTid);
         }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
@@ -743,6 +775,12 @@
         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
         final long identityToken = Binder.clearCallingIdentity();
+        if (intConnTracingEnabled()) {
+            logTraceIntConn("findFocus",
+                    accessibilityNodeId + ";" + focusType + ";" + partialInteractiveRegion + ";"
+                    + interactionId + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid
+                    + ";" + interrogatingTid + ";" + spec);
+        }
         try {
             connection.getRemote().findFocus(accessibilityNodeId, focusType,
                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
@@ -768,12 +806,12 @@
             int direction, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".focusSearch",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("focusSearch",
                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
-                            + accessibilityNodeId + ";direction=" + direction + ";interactionId="
-                            + interactionId + ";callback=" + callback + ";interrogatingTid="
-                            + interrogatingTid);
+                    + accessibilityNodeId + ";direction=" + direction + ";interactionId="
+                    + interactionId + ";callback=" + callback + ";interrogatingTid="
+                    + interrogatingTid);
         }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
@@ -810,6 +848,12 @@
         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
         final long identityToken = Binder.clearCallingIdentity();
+        if (intConnTracingEnabled()) {
+            logTraceIntConn("focusSearch",
+                    accessibilityNodeId + ";" + direction + ";" + partialInteractiveRegion
+                    + ";" + interactionId + ";" + callback + ";" + mFetchFlags + ";"
+                    + interrogatingPid + ";" + interrogatingTid + ";" + spec);
+        }
         try {
             connection.getRemote().focusSearch(accessibilityNodeId, direction,
                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
@@ -832,17 +876,17 @@
 
     @Override
     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".sendGesture",
-                    "sequence=" + sequence + ";gestureSteps=" + gestureSteps);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn(
+                    "sendGesture", "sequence=" + sequence + ";gestureSteps=" + gestureSteps);
         }
     }
 
     @Override
     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".dispatchGesture", "sequence="
-                    + sequence + ";gestureSteps=" + gestureSteps + ";displayId=" + displayId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("dispatchGesture", "sequence=" + sequence + ";gestureSteps="
+                    + gestureSteps + ";displayId=" + displayId);
         }
     }
 
@@ -851,12 +895,12 @@
             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performAccessibilityAction",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("performAccessibilityAction",
                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
-                            + accessibilityNodeId + ";action=" + action + ";arguments=" + arguments
-                            + ";interactionId=" + interactionId + ";callback=" + callback
-                            + ";interrogatingTid=" + interrogatingTid);
+                    + accessibilityNodeId + ";action=" + action + ";arguments=" + arguments
+                    + ";interactionId=" + interactionId + ";callback=" + callback
+                    + ";interrogatingTid=" + interrogatingTid);
         }
         final int resolvedWindowId;
         synchronized (mLock) {
@@ -879,9 +923,8 @@
 
     @Override
     public boolean performGlobalAction(int action) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performGlobalAction",
-                    "action=" + action);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("performGlobalAction", "action=" + action);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -893,8 +936,8 @@
 
     @Override
     public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSystemActions");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getSystemActions", "");
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -906,9 +949,8 @@
 
     @Override
     public boolean isFingerprintGestureDetectionAvailable() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(
-                    TRACE_A11Y_SERVICE_CONNECTION + ".isFingerprintGestureDetectionAvailable");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("isFingerprintGestureDetectionAvailable", "");
         }
         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
             return false;
@@ -923,9 +965,8 @@
 
     @Override
     public float getMagnificationScale(int displayId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationScale",
-                    "displayId=" + displayId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getMagnificationScale", "displayId=" + displayId);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -942,9 +983,8 @@
 
     @Override
     public Region getMagnificationRegion(int displayId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationRegion",
-                    "displayId=" + displayId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getMagnificationRegion", "displayId=" + displayId);
         }
         synchronized (mLock) {
             final Region region = Region.obtain();
@@ -970,9 +1010,8 @@
 
     @Override
     public float getMagnificationCenterX(int displayId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterX",
-                    "displayId=" + displayId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getMagnificationCenterX", "displayId=" + displayId);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -996,9 +1035,8 @@
 
     @Override
     public float getMagnificationCenterY(int displayId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterY",
-                    "displayId=" + displayId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getMagnificationCenterY", "displayId=" + displayId);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -1032,9 +1070,8 @@
 
     @Override
     public boolean resetMagnification(int displayId, boolean animate) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".resetMagnification",
-                    "displayId=" + displayId + ";animate=" + animate);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("resetMagnification", "displayId=" + displayId + ";animate=" + animate);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -1058,10 +1095,10 @@
     @Override
     public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
             float centerY, boolean animate) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationScaleAndCenter",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setMagnificationScaleAndCenter",
                     "displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
-                            + ";centerY=" + centerY + ";animate=" + animate);
+                    + ";centerY=" + centerY + ";animate=" + animate);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -1087,8 +1124,8 @@
 
     @Override
     public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationCallbackEnabled",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setMagnificationCallbackEnabled",
                     "displayId=" + displayId + ";enabled=" + enabled);
         }
         mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
@@ -1100,18 +1137,16 @@
 
     @Override
     public void setSoftKeyboardCallbackEnabled(boolean enabled) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardCallbackEnabled",
-                    "enabled=" + enabled);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setSoftKeyboardCallbackEnabled", "enabled=" + enabled);
         }
         mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
     }
 
     @Override
     public void takeScreenshot(int displayId, RemoteCallback callback) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".takeScreenshot",
-                    "displayId=" + displayId + ";callback=" + callback);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("takeScreenshot", "displayId=" + displayId + ";callback=" + callback);
         }
         final long currentTimestamp = SystemClock.uptimeMillis();
         if (mRequestTakeScreenshotTimestampMs != 0
@@ -1237,6 +1272,10 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final IBinder overlayWindowToken = new Binder();
+            if (wmTracingEnabled()) {
+                logTraceWM("addWindowToken",
+                        overlayWindowToken + ";TYPE_ACCESSIBILITY_OVERLAY;" + displayId + ";null");
+            }
             mWindowManagerService.addWindowToken(overlayWindowToken, TYPE_ACCESSIBILITY_OVERLAY,
                     displayId, null /* options */);
             synchronized (mLock) {
@@ -1263,6 +1302,10 @@
      */
     public void onDisplayRemoved(int displayId) {
         final long identity = Binder.clearCallingIdentity();
+        if (wmTracingEnabled()) {
+            logTraceWM(
+                    "addWindowToken", mOverlayWindowTokens.get(displayId) + ";true;" + displayId);
+        }
         try {
             mWindowManagerService.removeWindowToken(mOverlayWindowTokens.get(displayId), true,
                     displayId);
@@ -1282,9 +1325,8 @@
      */
     @Override
     public IBinder getOverlayWindowToken(int displayId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getOverlayWindowToken",
-                    "displayId=" + displayId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getOverlayWindowToken", "displayId=" + displayId);
         }
         synchronized (mLock) {
             return mOverlayWindowTokens.get(displayId);
@@ -1299,9 +1341,8 @@
      */
     @Override
     public int getWindowIdForLeashToken(@NonNull IBinder token) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindowIdForLeashToken",
-                    "token=" + token);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getWindowIdForLeashToken", "token=" + token);
         }
         synchronized (mLock) {
             return mA11yWindowManager.getWindowIdLocked(token);
@@ -1314,8 +1355,8 @@
             // Clear the proxy in the other process so this
             // IAccessibilityServiceConnection can be garbage collected.
             if (mServiceInterface != null) {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", "null, " + mId + ", null");
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("init", "null, " + mId + ", null");
                 }
                 mServiceInterface.init(null, mId, null);
             }
@@ -1465,9 +1506,8 @@
         }
 
         try {
-            if (mTrace.isA11yTracingEnabled()) {
-                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityEvent",
-                        event + ";" + serviceWantsEvent);
+            if (svcClientTracingEnabled()) {
+                logTraceSvcClient("onAccessibilityEvent", event + ";" + serviceWantsEvent);
             }
             listener.onAccessibilityEvent(event, serviceWantsEvent);
             if (DEBUG) {
@@ -1522,9 +1562,9 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onMagnificationChanged", displayId
-                            + ", " + region + ", " + scale + ", " + centerX + ", " + centerY);
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onMagnificationChanged", displayId + ", " + region + ", "
+                            + scale + ", " + centerX + ", " + centerY);
                 }
                 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY);
             } catch (RemoteException re) {
@@ -1541,9 +1581,8 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSoftKeyboardShowModeChanged",
-                            String.valueOf(showState));
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onSoftKeyboardShowModeChanged", String.valueOf(showState));
                 }
                 listener.onSoftKeyboardShowModeChanged(showState);
             } catch (RemoteException re) {
@@ -1557,9 +1596,8 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonClicked",
-                            String.valueOf(displayId));
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onAccessibilityButtonClicked", String.valueOf(displayId));
                 }
                 listener.onAccessibilityButtonClicked(displayId);
             } catch (RemoteException re) {
@@ -1579,9 +1617,8 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(
-                            TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonAvailabilityChanged",
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onAccessibilityButtonAvailabilityChanged",
                             String.valueOf(available));
                 }
                 listener.onAccessibilityButtonAvailabilityChanged(available);
@@ -1597,9 +1634,8 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onGesture",
-                            gestureInfo.toString());
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onGesture", gestureInfo.toString());
                 }
                 listener.onGesture(gestureInfo);
             } catch (RemoteException re) {
@@ -1613,8 +1649,8 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSystemActionsChanged");
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onSystemActionsChanged", "");
                 }
                 listener.onSystemActionsChanged();
             } catch (RemoteException re) {
@@ -1628,8 +1664,8 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".clearAccessibilityCache");
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("clearAccessibilityCache", "");
                 }
                 listener.clearAccessibilityCache();
             } catch (RemoteException re) {
@@ -1747,6 +1783,12 @@
                 LocalServices.getService(ActivityTaskManagerInternal.class)
                         .setFocusedActivity(activityToken);
             }
+            if (intConnTracingEnabled()) {
+                logTraceIntConn("performAccessibilityAction",
+                        accessibilityNodeId + ";" + action + ";" + arguments + ";" + interactionId
+                        + ";" + callback + ";" + mFetchFlags + ";" + interrogatingPid + ";"
+                        + interrogatingTid);
+            }
             connection.getRemote().performAccessibilityAction(accessibilityNodeId, action,
                     arguments, interactionId, callback, fetchFlags, interrogatingPid,
                     interrogatingTid);
@@ -1957,8 +1999,8 @@
 
     @Override
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setGestureDetectionPassthroughRegion",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setGestureDetectionPassthroughRegion",
                     "displayId=" + displayId + ";region=" + region);
         }
         mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
@@ -1966,8 +2008,8 @@
 
     @Override
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setTouchExplorationPassthroughRegion",
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setTouchExplorationPassthroughRegion",
                     "displayId=" + displayId + ";region=" + region);
         }
         mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
@@ -1975,20 +2017,56 @@
 
     @Override
     public void setFocusAppearance(int strokeWidth, int color) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setFocusAppearance",
-                    "strokeWidth=" + strokeWidth + ";color=" + color);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setFocusAppearance", "strokeWidth=" + strokeWidth + ";color=" + color);
         }
     }
 
     @Override
-    public void logTrace(long timestamp, String where, String callingParams, int processId,
-            long threadId, int callingUid, Bundle callingStack) {
-        if (mTrace.isA11yTracingEnabled()) {
+    public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
+            int processId, long threadId, int callingUid, Bundle callingStack) {
+        if (mTrace.isA11yTracingEnabledForTypes(loggingTypes)) {
             ArrayList<StackTraceElement> list =
                     (ArrayList<StackTraceElement>) callingStack.getSerializable(CALL_STACK);
-            mTrace.logTrace(timestamp, where, callingParams, processId, threadId, callingUid,
-                    list.toArray(new StackTraceElement[list.size()]));
+            HashSet<String> ignoreList =
+                    (HashSet<String>) callingStack.getSerializable(IGNORE_CALL_STACK);
+            mTrace.logTrace(timestamp, where, loggingTypes, callingParams, processId, threadId,
+                    callingUid, list.toArray(new StackTraceElement[list.size()]), ignoreList);
         }
     }
+
+    protected boolean svcClientTracingEnabled() {
+        return mTrace.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT);
+    }
+
+    protected void logTraceSvcClient(String methodName, String params) {
+        mTrace.logTrace(TRACE_SVC_CLIENT + "." + methodName,
+                    FLAGS_ACCESSIBILITY_SERVICE_CLIENT, params);
+    }
+
+    protected boolean svcConnTracingEnabled() {
+        return mTrace.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CONNECTION);
+    }
+
+    protected void logTraceSvcConn(String methodName, String params) {
+        mTrace.logTrace(TRACE_SVC_CONN + "." + methodName,
+                FLAGS_ACCESSIBILITY_SERVICE_CONNECTION, params);
+    }
+
+    protected boolean intConnTracingEnabled() {
+        return mTrace.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION);
+    }
+
+    protected void logTraceIntConn(String methodName, String params) {
+        mTrace.logTrace(LOG_TAG + "." + methodName,
+                FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION, params);
+    }
+
+    protected boolean wmTracingEnabled() {
+        return mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL);
+    }
+
+    protected void logTraceWM(String methodName, String params) {
+        mTrace.logTrace(TRACE_WM + "." + methodName, FLAGS_WINDOW_MANAGER_INTERNAL, params);
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 7403af7..bae2e1a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 
+import android.accessibilityservice.AccessibilityTrace;
 import android.annotation.MainThread;
 import android.content.Context;
 import android.graphics.Region;
@@ -224,7 +225,12 @@
             Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
         }
-
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(
+                AccessibilityTrace.FLAGS_INPUT_FILTER)) {
+            mAms.getTraceManager().logTrace(TAG + ".onInputEvent",
+                    AccessibilityTrace.FLAGS_INPUT_FILTER,
+                    "event=" + event + ";policyFlags=" + policyFlags);
+        }
         if (mEventHandler.size() == 0) {
             if (DEBUG) Slog.d(TAG, "No mEventHandler for event " + event);
             super.onInputEvent(event, policyFlags);
@@ -424,7 +430,8 @@
         final ArrayList<Display> displaysList = mAms.getValidDisplayList();
 
         if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
-            mAutoclickController = new AutoclickController(mContext, mUserId);
+            mAutoclickController = new AutoclickController(
+                    mContext, mUserId, mAms.getTraceManager());
             addFirstEventHandlerForAllDisplays(displaysList, mAutoclickController);
         }
 
@@ -462,7 +469,7 @@
 
             if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
                 MotionEventInjector injector = new MotionEventInjector(
-                        mContext.getMainLooper());
+                        mContext.getMainLooper(), mAms.getTraceManager());
                 addFirstEventHandler(displayId, injector);
                 mMotionEventInjectors.put(displayId, injector);
             }
@@ -563,15 +570,15 @@
             final Context uiContext = displayContext.createWindowContext(
                     TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, null /* options */);
             magnificationGestureHandler = new WindowMagnificationGestureHandler(uiContext,
-                    mAms.getWindowMagnificationMgr(), mAms.getMagnificationController(),
-                    detectControlGestures, triggerable,
+                    mAms.getWindowMagnificationMgr(), mAms.getTraceManager(),
+                    mAms.getMagnificationController(), detectControlGestures, triggerable,
                     displayId);
         } else {
             final Context uiContext = displayContext.createWindowContext(
                     TYPE_MAGNIFICATION_OVERLAY, null /* options */);
             magnificationGestureHandler = new FullScreenMagnificationGestureHandler(uiContext,
-                    mAms.getFullScreenMagnificationController(), mAms.getMagnificationController(),
-                    detectControlGestures, triggerable,
+                    mAms.getFullScreenMagnificationController(), mAms.getTraceManager(),
+                    mAms.getMagnificationController(), detectControlGestures, triggerable,
                     new WindowMagnificationPromptController(displayContext, mUserId), displayId);
         }
         return magnificationGestureHandler;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index f631988..ce8943f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,6 +16,15 @@
 
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER_CLIENT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_FINGERPRINT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROADCAST_RECEIVER;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
 import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
@@ -289,8 +298,8 @@
         mContext = context;
         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
-        mTraceManager = new AccessibilityTraceManager(
-                mWindowManagerService.getAccessibilityController(), this);
+        mTraceManager = AccessibilityTraceManager.getInstance(
+                mWindowManagerService.getAccessibilityController(), this, mLock);
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = packageManager;
@@ -311,8 +320,8 @@
         mContext = context;
         mPowerManager = context.getSystemService(PowerManager.class);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
-        mTraceManager = new AccessibilityTraceManager(
-                mWindowManagerService.getAccessibilityController(), this);
+        mTraceManager = AccessibilityTraceManager.getInstance(
+                mWindowManagerService.getAccessibilityController(), this, mLock);
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = mContext.getPackageManager();
@@ -324,7 +333,7 @@
         mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext,
                 this);
         mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
-                mWindowManagerService, this, mSecurityPolicy, this);
+                mWindowManagerService, this, mSecurityPolicy, this, mTraceManager);
         mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
         mMagnificationController = new MagnificationController(this, mLock, mContext);
         init();
@@ -339,26 +348,16 @@
 
     @Override
     public int getCurrentUserIdLocked() {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getCurrentUserIdLocked");
-        }
         return mCurrentUserId;
     }
 
     @Override
     public boolean isAccessibilityButtonShown() {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".isAccessibilityButtonShown");
-        }
         return mIsAccessibilityButtonShown;
     }
 
     @Override
     public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(
-                    LOG_TAG + ".onServiceInfoChangedLocked", "userState=" + userState);
-        }
         mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId,
                 userState.mBoundServices);
         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
@@ -424,8 +423,9 @@
         PackageMonitor monitor = new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
-                if (mTraceManager.isA11yTracingEnabled()) {
-                    mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged");
+                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+                    mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged",
+                            FLAGS_PACKAGE_BROADCAST_RECEIVER);
                 }
 
                 synchronized (mLock) {
@@ -452,8 +452,9 @@
                 // mBindingServices in binderDied() during updating. Remove services from  this
                 // package from mBindingServices, and then update the user state to re-bind new
                 // versions of them.
-                if (mTraceManager.isA11yTracingEnabled()) {
+                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
                     mTraceManager.logTrace(LOG_TAG + ".PM.onPackageUpdateFinished",
+                            FLAGS_PACKAGE_BROADCAST_RECEIVER,
                             "packageName=" + packageName + ";uid=" + uid);
                 }
                 synchronized (mLock) {
@@ -485,8 +486,9 @@
 
             @Override
             public void onPackageRemoved(String packageName, int uid) {
-                if (mTraceManager.isA11yTracingEnabled()) {
+                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
                     mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
+                            FLAGS_PACKAGE_BROADCAST_RECEIVER,
                             "packageName=" + packageName + ";uid=" + uid);
                 }
 
@@ -529,8 +531,9 @@
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages,
                     int uid, boolean doit) {
-                if (mTraceManager.isA11yTracingEnabled()) {
+                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
                     mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
+                            FLAGS_PACKAGE_BROADCAST_RECEIVER,
                             "intent=" + intent + ";packages=" + packages + ";uid=" + uid
                             + ";doit=" + doit);
                 }
@@ -580,8 +583,8 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (mTraceManager.isA11yTracingEnabled()) {
-                    mTraceManager.logTrace(LOG_TAG + ".BR.onReceive",
+                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_USER_BROADCAST_RECEIVER)) {
+                    mTraceManager.logTrace(LOG_TAG + ".BR.onReceive", FLAGS_USER_BROADCAST_RECEIVER,
                             "context=" + context + ";intent=" + intent);
                 }
 
@@ -668,8 +671,8 @@
 
     @Override
     public long addClient(IAccessibilityManagerClient callback, int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".addClient",
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".addClient", FLAGS_ACCESSIBILITY_MANAGER,
                     "callback=" + callback + ";userId=" + userId);
         }
 
@@ -739,11 +742,12 @@
 
     @Override
     public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEvent",
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEvent", FLAGS_ACCESSIBILITY_MANAGER,
                     "event=" + event + ";userId=" + userId);
         }
         boolean dispatchEvent = false;
+        int resolvedUserId;
 
         synchronized (mLock) {
             if (event.getWindowId() ==
@@ -759,8 +763,7 @@
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
             // performs the current profile parent resolution.
-            final int resolvedUserId = mSecurityPolicy
-                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
+            resolvedUserId = mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
             // Make sure the reported package is one the caller has access to.
             event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
@@ -792,17 +795,23 @@
             int displayId = Display.INVALID_DISPLAY;
             synchronized (mLock) {
                 final int windowId = event.getWindowId();
-                if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
-                        && windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+                if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
                     displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(
-                            mCurrentUserId, windowId);
+                            resolvedUserId, windowId);
+                    event.setDisplayId(displayId);
                 }
-                if (displayId != Display.INVALID_DISPLAY
+
+                if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+                        && displayId != Display.INVALID_DISPLAY
                         && mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
                     shouldComputeWindows = true;
                 }
             }
             if (shouldComputeWindows) {
+                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
+                    mTraceManager.logTrace("WindowManagerInternal.computeWindowsForAccessibility",
+                            FLAGS_WINDOW_MANAGER_INTERNAL, "display=" + displayId);
+                }
                 final WindowManagerInternal wm = LocalServices.getService(
                         WindowManagerInternal.class);
                 wm.computeWindowsForAccessibility(displayId);
@@ -835,9 +844,9 @@
      */
     @Override
     public void registerSystemAction(RemoteAction action, int actionId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".registerSystemAction",
-                    "action=" + action + ";actionId=" + actionId);
+                    FLAGS_ACCESSIBILITY_MANAGER, "action=" + action + ";actionId=" + actionId);
         }
         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
         getSystemActionPerformer().registerSystemAction(actionId, action);
@@ -850,8 +859,9 @@
      */
     @Override
     public void unregisterSystemAction(int actionId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction", "actionId=" + actionId);
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction",
+                    FLAGS_ACCESSIBILITY_MANAGER, "actionId=" + actionId);
         }
         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
         getSystemActionPerformer().unregisterSystemAction(actionId);
@@ -867,9 +877,9 @@
 
     @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList",
-                    "userId=" + userId);
+                    FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId);
         }
 
         final int resolvedUserId;
@@ -903,8 +913,9 @@
     @Override
     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
             int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList",
+                    FLAGS_ACCESSIBILITY_MANAGER,
                     "feedbackType=" + feedbackType + ";userId=" + userId);
         }
 
@@ -936,8 +947,9 @@
 
     @Override
     public void interrupt(int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".interrupt", "userId=" + userId);
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".interrupt",
+                    FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId);
         }
 
         List<IAccessibilityServiceClient> interfacesToInterrupt;
@@ -966,8 +978,10 @@
         }
         for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
             try {
-                if (mTraceManager.isA11yTracingEnabled()) {
-                    mTraceManager.logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt");
+                if (mTraceManager.isA11yTracingEnabledForTypes(
+                        FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
+                    mTraceManager.logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt",
+                            FLAGS_ACCESSIBILITY_SERVICE_CLIENT);
                 }
                 interfacesToInterrupt.get(i).onInterrupt();
             } catch (RemoteException re) {
@@ -981,8 +995,9 @@
     public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken,
             IAccessibilityInteractionConnection connection, String packageName,
             int userId) throws RemoteException {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".addAccessibilityInteractionConnection",
+                    FLAGS_ACCESSIBILITY_MANAGER,
                     "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection="
                             + connection + "; packageName=" + packageName + ";userId=" + userId);
         }
@@ -993,9 +1008,9 @@
 
     @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection",
-                    "window=" + window);
+                    FLAGS_ACCESSIBILITY_MANAGER, "window=" + window);
         }
         mA11yWindowManager.removeAccessibilityInteractionConnection(window);
     }
@@ -1003,9 +1018,9 @@
     @Override
     public void setPictureInPictureActionReplacingConnection(
             IAccessibilityInteractionConnection connection) throws RemoteException {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection",
-                    "connection=" + connection);
+                    FLAGS_ACCESSIBILITY_MANAGER, "connection=" + connection);
         }
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.MODIFY_ACCESSIBILITY_DATA,
                 SET_PIP_ACTION_REPLACEMENT);
@@ -1017,10 +1032,11 @@
             IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo,
             int flags) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService", "owner=" + owner
-                    + ";serviceClient=" + serviceClient + ";accessibilityServiceInfo="
-                    + accessibilityServiceInfo + ";flags=" + flags);
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService",
+                    FLAGS_ACCESSIBILITY_MANAGER,
+                    "owner=" + owner + ";serviceClient=" + serviceClient
+                    + ";accessibilityServiceInfo=" + accessibilityServiceInfo + ";flags=" + flags);
         }
 
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
@@ -1037,9 +1053,9 @@
 
     @Override
     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".unregisterUiTestAutomationService",
-                    "serviceClient=" + serviceClient);
+                    FLAGS_ACCESSIBILITY_MANAGER, "serviceClient=" + serviceClient);
         }
         synchronized (mLock) {
             mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient);
@@ -1049,15 +1065,20 @@
     @Override
     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
             ComponentName service, boolean touchExplorationEnabled) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(
                     LOG_TAG + ".temporaryEnableAccessibilityStateUntilKeyguardRemoved",
+                    FLAGS_ACCESSIBILITY_MANAGER,
                     "service=" + service + ";touchExplorationEnabled=" + touchExplorationEnabled);
         }
 
         mSecurityPolicy.enforceCallingPermission(
                 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
                 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
+            mTraceManager.logTrace("WindowManagerInternal.isKeyguardLocked",
+                    FLAGS_WINDOW_MANAGER_INTERNAL);
+        }
         if (!mWindowManagerService.isKeyguardLocked()) {
             return;
         }
@@ -1083,9 +1104,9 @@
 
     @Override
     public IBinder getWindowToken(int windowId, int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".getWindowToken",
-                    "windowId=" + windowId + ";userId=" + userId);
+                    FLAGS_ACCESSIBILITY_MANAGER, "windowId=" + windowId + ";userId=" + userId);
         }
 
         mSecurityPolicy.enforceCallingPermission(
@@ -1127,8 +1148,9 @@
      */
     @Override
     public void notifyAccessibilityButtonClicked(int displayId, String targetName) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked",
+                    FLAGS_ACCESSIBILITY_MANAGER,
                     "displayId=" + displayId + ";targetName=" + targetName);
         }
 
@@ -1157,9 +1179,9 @@
      */
     @Override
     public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged",
-                    "shown=" + shown);
+                    FLAGS_ACCESSIBILITY_MANAGER, "shown=" + shown);
         }
 
         mSecurityPolicy.enforceCallingOrSelfPermission(
@@ -1190,10 +1212,6 @@
      */
     @Override
     public void onSystemActionsChanged() {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".onSystemActionsChanged");
-        }
-
         synchronized (mLock) {
             AccessibilityUserState state = getCurrentUserStateLocked();
             notifySystemActionsChangedLocked(state);
@@ -1256,11 +1274,6 @@
 
     @Override
     public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getMotionEventInjectorForDisplayLocked",
-                    "displayId=" + displayId);
-        }
-
         final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
         MotionEventInjector motionEventInjector = null;
         while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
@@ -1323,6 +1336,10 @@
         synchronized (mLock) {
             token = getWindowToken(windowId, mCurrentUserId);
         }
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
+            mTraceManager.logTrace("WindowManagerInternal.getWindowFrame",
+                    FLAGS_WINDOW_MANAGER_INTERNAL, "token=" + token + ";outBounds=" + outBounds);
+        }
         mWindowManagerService.getWindowFrame(token, outBounds);
         if (!outBounds.isEmpty()) {
             return true;
@@ -1471,7 +1488,7 @@
     private int getClientStateLocked(AccessibilityUserState userState) {
         return userState.getClientStateLocked(
             mUiAutomationManager.isUiAutomationRunningLocked(),
-            mTraceManager.isA11yTracingEnabled());
+            mTraceManager.getTraceStateForAccessibilityManagerClientState());
     }
 
     private InteractionBridge getInteractionBridge() {
@@ -1681,6 +1698,10 @@
     }
 
     private void updateRelevantEventsLocked(AccessibilityUserState userState) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
+            mTraceManager.logTrace(LOG_TAG + ".updateRelevantEventsLocked",
+                    FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState);
+        }
         mMainHandler.post(() -> {
             broadcastToClients(userState, ignoreRemoteException(client -> {
                 int relevantEventTypes;
@@ -1830,12 +1851,6 @@
     @Override
     public void persistComponentNamesToSettingLocked(String settingName,
             Set<ComponentName> componentNames, int userId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".persistComponentNamesToSettingLocked",
-                    "settingName=" + settingName + ";componentNames=" + componentNames + ";userId="
-                            + userId);
-        }
-
         persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames,
                 componentName -> componentName.flattenToShortString());
     }
@@ -1960,7 +1975,7 @@
         }
     }
 
-    private void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) {
+    void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) {
         final int clientState = getClientStateLocked(userState);
         if (userState.getLastSentClientStateLocked() != clientState
                 && (mGlobalClients.getRegisteredCallbackCount() > 0
@@ -1983,6 +1998,10 @@
 
     private void sendStateToClients(int clientState,
             RemoteCallbackList<IAccessibilityManagerClient> clients) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) {
+            mTraceManager.logTrace(LOG_TAG + ".sendStateToClients",
+                    FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "clientState=" + clientState);
+        }
         clients.broadcast(ignoreRemoteException(
                 client -> client.setState(clientState)));
     }
@@ -2003,6 +2022,10 @@
 
     private void notifyClientsOfServicesStateChange(
             RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) {
+            mTraceManager.logTrace(LOG_TAG + ".notifyClientsOfServicesStateChange",
+                    FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "uiTimeout=" + uiTimeout);
+        }
         clients.broadcast(ignoreRemoteException(
                 client -> client.notifyServicesStateChanged(uiTimeout)));
     }
@@ -2082,6 +2105,12 @@
             }
         }
         if (setInputFilter) {
+            if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL
+                    | FLAGS_INPUT_FILTER)) {
+                mTraceManager.logTrace("WindowManagerInternal.setInputFilter",
+                        FLAGS_WINDOW_MANAGER_INTERNAL | FLAGS_INPUT_FILTER,
+                        "inputFilter=" + inputFilter);
+            }
             mWindowManagerService.setInputFilter(inputFilter);
         }
     }
@@ -2805,26 +2834,21 @@
     @GuardedBy("mLock")
     @Override
     public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getCompatibleMagnificationSpecLocked",
-                    "windowId=" + windowId);
-        }
-
         IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
                 mCurrentUserId, windowId);
         if (windowToken != null) {
-            return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
-                    windowToken);
+            if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
+                mTraceManager.logTrace(LOG_TAG + ".getCompatibleMagnificationSpecForWindow",
+                        FLAGS_WINDOW_MANAGER_INTERNAL, "windowToken=" + windowToken);
+            }
+
+            return mWindowManagerService.getCompatibleMagnificationSpecForWindow(windowToken);
         }
         return null;
     }
 
     @Override
     public KeyEventDispatcher getKeyEventDispatcher() {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getKeyEventDispatcher");
-        }
-
         if (mKeyEventDispatcher == null) {
             mKeyEventDispatcher = new KeyEventDispatcher(
                     mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock,
@@ -2837,13 +2861,6 @@
     @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
     public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
             int flags) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getPendingIntentActivity",
-                    "context=" + context + ";requestCode=" + requestCode + ";intent=" + intent
-                            + ";flags=" + flags);
-        }
-
-
         return PendingIntent.getActivity(context, requestCode, intent, flags);
     }
 
@@ -2858,9 +2875,9 @@
      */
     @Override
     public void performAccessibilityShortcut(String targetName) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".performAccessibilityShortcut",
-                    "targetName=" + targetName);
+                    FLAGS_ACCESSIBILITY_MANAGER, "targetName=" + targetName);
         }
 
         if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)
@@ -3048,9 +3065,9 @@
 
     @Override
     public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets",
-                    "shortcutType=" + shortcutType);
+                    FLAGS_ACCESSIBILITY_MANAGER, "shortcutType=" + shortcutType);
         }
 
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
@@ -3122,11 +3139,6 @@
 
     @Override
     public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEventForCurrentUserLocked",
-                    "event=" + event);
-        }
-
         sendAccessibilityEventLocked(event, mCurrentUserId);
     }
 
@@ -3148,8 +3160,10 @@
      */
     @Override
     public boolean sendFingerprintGesture(int gestureKeyCode) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(
+                FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT)) {
             mTraceManager.logTrace(LOG_TAG + ".sendFingerprintGesture",
+                    FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT,
                     "gestureKeyCode=" + gestureKeyCode);
         }
 
@@ -3174,9 +3188,9 @@
      */
     @Override
     public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityWindowId",
-                    "windowToken=" + windowToken);
+                    FLAGS_ACCESSIBILITY_MANAGER, "windowToken=" + windowToken);
         }
 
         synchronized (mLock) {
@@ -3196,8 +3210,9 @@
      */
     @Override
     public long getRecommendedTimeoutMillis() {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getRecommendedTimeoutMillis");
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(
+                    LOG_TAG + ".getRecommendedTimeoutMillis", FLAGS_ACCESSIBILITY_MANAGER);
         }
 
         synchronized(mLock) {
@@ -3214,8 +3229,10 @@
     @Override
     public void setWindowMagnificationConnection(
             IWindowMagnificationConnection connection) throws RemoteException {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(
+                FLAGS_ACCESSIBILITY_MANAGER | FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
             mTraceManager.logTrace(LOG_TAG + ".setWindowMagnificationConnection",
+                    FLAGS_ACCESSIBILITY_MANAGER | FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
                     "connection=" + connection);
         }
 
@@ -3249,9 +3266,9 @@
 
     @Override
     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
-        if (mTraceManager.isA11yTracingEnabled()) {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
             mTraceManager.logTrace(LOG_TAG + ".associateEmbeddedHierarchy",
-                    "host=" + host + ";embedded=" + embedded);
+                    FLAGS_ACCESSIBILITY_MANAGER, "host=" + host + ";embedded=" + embedded);
         }
 
         synchronized (mLock) {
@@ -3261,8 +3278,9 @@
 
     @Override
     public void disassociateEmbeddedHierarchy(@NonNull IBinder token) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy", "token=" + token);
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy",
+                    FLAGS_ACCESSIBILITY_MANAGER, "token=" + token);
         }
 
         synchronized (mLock) {
@@ -3274,7 +3292,11 @@
      * Gets the stroke width of the focus rectangle.
      * @return The stroke width.
      */
+    @Override
     public int getFocusStrokeWidth() {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".getFocusStrokeWidth", FLAGS_ACCESSIBILITY_MANAGER);
+        }
         synchronized (mLock) {
             final AccessibilityUserState userState = getCurrentUserStateLocked();
 
@@ -3286,7 +3308,11 @@
      * Gets the color of the focus rectangle.
      * @return The color.
      */
+    @Override
     public int getFocusColor() {
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
+            mTraceManager.logTrace(LOG_TAG + ".getFocusColor", FLAGS_ACCESSIBILITY_MANAGER);
+        }
         synchronized (mLock) {
             final AccessibilityUserState userState = getCurrentUserStateLocked();
 
@@ -3350,9 +3376,6 @@
 
     @Override
     public FullScreenMagnificationController getFullScreenMagnificationController() {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".getFullScreenMagnificationController");
-        }
         synchronized (mLock) {
             return mMagnificationController.getFullScreenMagnificationController();
         }
@@ -3360,11 +3383,6 @@
 
     @Override
     public void onClientChangeLocked(boolean serviceInfoChanged) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".onClientChangeLocked",
-                    "serviceInfoChanged=" + serviceInfoChanged);
-        }
-
         AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
         onUserStateChangedLocked(userState);
         if (serviceInfoChanged) {
@@ -3891,11 +3909,6 @@
 
     @Override
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".setGestureDetectionPassthroughRegion",
-                    "displayId=" + displayId + ";region=" + region);
-        }
-
         mMainHandler.sendMessage(
                 obtainMessage(
                         AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal,
@@ -3906,11 +3919,6 @@
 
     @Override
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
-        if (mTraceManager.isA11yTracingEnabled()) {
-            mTraceManager.logTrace(LOG_TAG + ".setTouchExplorationPassthroughRegion",
-                    "displayId=" + displayId + ";region=" + region);
-        }
-
         mMainHandler.sendMessage(
                 obtainMessage(
                         AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal,
@@ -3939,7 +3947,10 @@
         if (userState.mUserId != mCurrentUserId) {
             return;
         }
-
+        if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
+            mTraceManager.logTrace(LOG_TAG + ".updateFocusAppearanceDataLocked",
+                    FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState);
+        }
         mMainHandler.post(() -> {
             broadcastToClients(userState, ignoreRemoteException(client -> {
                 client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(),
@@ -3949,7 +3960,7 @@
 
     }
 
-    AccessibilityTraceManager getTraceManager() {
+    public AccessibilityTraceManager getTraceManager() {
         return mTraceManager;
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index dc2628f..a7f0f1c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -534,7 +534,8 @@
 
         int servicePackageUid = serviceInfo.applicationInfo.uid;
         if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE,
-                servicePackageUid, serviceInfo.packageName) != AppOpsManager.MODE_ALLOWED) {
+                servicePackageUid, serviceInfo.packageName, null, null)
+                != AppOpsManager.MODE_ALLOWED) {
             Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName(
                     serviceInfo.packageName, serviceInfo.name).flattenToShortString()
                     + ": disallowed by AppOps");
@@ -559,17 +560,21 @@
             return true;
         }
 
-        final int uid = resolveInfo.serviceInfo.applicationInfo.uid;
+        final int servicePackageUid = resolveInfo.serviceInfo.applicationInfo.uid;
+        final int callingPid = Binder.getCallingPid();
         final long identityToken = Binder.clearCallingIdentity();
+        final String attributionTag = service.getAttributionTag();
         try {
             // For the caller is system, just block the data to a11y services.
-            if (OWN_PROCESS_ID == Binder.getCallingPid()) {
+            if (OWN_PROCESS_ID == callingPid) {
                 return mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
-                        uid, packageName) == AppOpsManager.MODE_ALLOWED;
+                        servicePackageUid, packageName, attributionTag, null)
+                        == AppOpsManager.MODE_ALLOWED;
             }
 
             return mAppOpsManager.noteOp(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
-                    uid, packageName) == AppOpsManager.MODE_ALLOWED;
+                    servicePackageUid, packageName, attributionTag, null)
+                    == AppOpsManager.MODE_ALLOWED;
         } finally {
             Binder.restoreCallingIdentity(identityToken);
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 7d75b73..467cab5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -20,6 +20,7 @@
 
 import android.Manifest;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -53,10 +54,7 @@
  */
 class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
     private static final String LOG_TAG = "AccessibilityServiceConnection";
-    private static final String TRACE_A11Y_SERVICE_CONNECTION =
-            LOG_TAG + ".IAccessibilityServiceConnection";
-    private static final String TRACE_A11Y_SERVICE_CLIENT =
-            LOG_TAG + ".IAccessibilityServiceClient";
+
     /*
      Holding a weak reference so there isn't a loop of references. AccessibilityUserState keeps
      lists of bound and binding services. These are freed on user changes, but just in case it
@@ -137,8 +135,8 @@
 
     @Override
     public void disableSelf() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".disableSelf");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("disableSelf", "");
         }
         synchronized (mLock) {
             AccessibilityUserState userState = mUserStateWeakReference.get();
@@ -218,9 +216,9 @@
             return;
         }
         try {
-            if (mTrace.isA11yTracingEnabled()) {
-                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", this + ", " + mId + ", "
-                        + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
+            if (svcClientTracingEnabled()) {
+                logTraceSvcClient("init",
+                        this + "," + mId + "," + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
             }
             serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
         } catch (RemoteException re) {
@@ -264,9 +262,8 @@
 
     @Override
     public boolean setSoftKeyboardShowMode(int showMode) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardShowMode",
-                    "showMode=" + showMode);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("setSoftKeyboardShowMode", "showMode=" + showMode);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -280,8 +277,8 @@
 
     @Override
     public int getSoftKeyboardShowMode() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSoftKeyboardShowMode");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("getSoftKeyboardShowMode", "");
         }
         final AccessibilityUserState userState = mUserStateWeakReference.get();
         return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0;
@@ -289,9 +286,8 @@
 
     @Override
     public boolean switchToInputMethod(String imeId) {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".switchToInputMethod",
-                    "imeId=" + imeId);
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("switchToInputMethod", "imeId=" + imeId);
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -311,8 +307,8 @@
 
     @Override
     public boolean isAccessibilityButtonAvailable() {
-        if (mTrace.isA11yTracingEnabled()) {
-            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".isAccessibilityButtonAvailable");
+        if (svcConnTracingEnabled()) {
+            logTraceSvcConn("isAccessibilityButtonAvailable", "");
         }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -373,9 +369,9 @@
         }
         if (serviceInterface != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT
-                            + ".onFingerprintCapturingGesturesChanged", String.valueOf(active));
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient(
+                            "onFingerprintCapturingGesturesChanged", String.valueOf(active));
                 }
                 mServiceInterface.onFingerprintCapturingGesturesChanged(active);
             } catch (RemoteException e) {
@@ -394,9 +390,8 @@
         }
         if (serviceInterface != null) {
             try {
-                if (mTrace.isA11yTracingEnabled()) {
-                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onFingerprintGesture",
-                            String.valueOf(gesture));
+                if (svcClientTracingEnabled()) {
+                    logTraceSvcClient("onFingerprintGesture", String.valueOf(gesture));
                 }
                 mServiceInterface.onFingerprintGesture(gesture);
             } catch (RemoteException e) {
@@ -410,15 +405,17 @@
             if (mSecurityPolicy.canPerformGestures(this)) {
                 MotionEventInjector motionEventInjector =
                         mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
+                if (wmTracingEnabled()) {
+                    logTraceWM("isTouchOrFaketouchDevice", "");
+                }
                 if (motionEventInjector != null
                         && mWindowManagerService.isTouchOrFaketouchDevice()) {
                     motionEventInjector.injectEvents(
                             gestureSteps.getList(), mServiceInterface, sequence, displayId);
                 } else {
                     try {
-                        if (mTrace.isA11yTracingEnabled()) {
-                            mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onPerformGestureResult",
-                                    sequence + ", false");
+                        if (svcClientTracingEnabled()) {
+                            logTraceSvcClient("onPerformGestureResult", sequence + ", false");
                         }
                         mServiceInterface.onPerformGestureResult(sequence, false);
                     } catch (RemoteException re) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
index 6396960..8cf5547 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
@@ -60,7 +60,7 @@
             }
             case "start-trace":
             case "stop-trace":
-                return mService.getTraceManager().onShellCommand(cmd);
+                return mService.getTraceManager().onShellCommand(cmd, this);
         }
         return -1;
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java
deleted file mode 100644
index 0391413..0000000
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java
+++ /dev/null
@@ -1,66 +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.accessibility;
-
-/**
- * Interface to log accessibility trace.
- */
-public interface AccessibilityTrace {
-    /**
-     * Whether the trace is enabled.
-     */
-    boolean isA11yTracingEnabled();
-
-    /**
-     * Start tracing.
-     */
-    void startTrace();
-
-    /**
-     * Stop tracing.
-     */
-    void stopTrace();
-
-    /**
-     * Log one trace entry.
-     * @param where A string to identify this log entry, which can be used to filter/search
-     *        through the tracing file.
-     */
-    void logTrace(String where);
-
-    /**
-     * Log one trace entry.
-     * @param where A string to identify this log entry, which can be used to filter/search
-     *        through the tracing file.
-     * @param callingParams The parameters for the method to be logged.
-     */
-    void logTrace(String where, String callingParams);
-
-    /**
-     * Log one trace entry. Accessibility services using AccessibilityInteractionClient to
-     * make screen content related requests use this API to log entry when receive callback.
-     * @param timestamp The timestamp when a callback is received.
-     * @param where A string to identify this log entry, which can be used to filter/search
-     *        through the tracing file.
-     * @param callingParams The parameters for the callback.
-     * @param processId The process id of the calling component.
-     * @param threadId The threadId of the calling component.
-     * @param callingUid The calling uid of the callback.
-     * @param callStack The call stack of the callback.
-     */
-    void logTrace(long timestamp, String where, String callingParams, int processId,
-            long threadId, int callingUid, StackTraceElement[] callStack);
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityTraceManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityTraceManager.java
index 6105e8a..51e01ea 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityTraceManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityTraceManager.java
@@ -15,72 +15,197 @@
  */
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CLIENT;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER_CLIENT_STATES;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_LOGGING_ALL;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_LOGGING_NONE;
+import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED;
+import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED;
+import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED;
+import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED;
+
+import android.accessibilityservice.AccessibilityTrace;
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.os.Binder;
+import android.os.ShellCommand;
 
 import com.android.server.wm.WindowManagerInternal;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * Manager of accessibility trace.
  */
-class AccessibilityTraceManager implements AccessibilityTrace {
+public class AccessibilityTraceManager implements AccessibilityTrace {
     private final WindowManagerInternal.AccessibilityControllerInternal mA11yController;
     private final AccessibilityManagerService mService;
+    private final Object mA11yMSLock;
 
-    AccessibilityTraceManager(
+    private long mEnabledLoggingFlags;
+
+    private static AccessibilityTraceManager sInstance = null;
+
+    @MainThread
+    static AccessibilityTraceManager getInstance(
             @NonNull WindowManagerInternal.AccessibilityControllerInternal a11yController,
-            @NonNull AccessibilityManagerService service) {
+            @NonNull AccessibilityManagerService service,
+            @NonNull Object lock) {
+        if (sInstance == null) {
+            sInstance = new AccessibilityTraceManager(a11yController, service, lock);
+        }
+        return sInstance;
+    }
+
+    private AccessibilityTraceManager(
+            @NonNull WindowManagerInternal.AccessibilityControllerInternal a11yController,
+            @NonNull AccessibilityManagerService service,
+            @NonNull Object lock) {
         mA11yController = a11yController;
         mService = service;
+        mA11yMSLock = lock;
+        mEnabledLoggingFlags = FLAGS_LOGGING_NONE;
     }
 
     @Override
     public boolean isA11yTracingEnabled() {
-        return mA11yController.isAccessibilityTracingEnabled();
+        synchronized (mA11yMSLock) {
+            return mEnabledLoggingFlags != FLAGS_LOGGING_NONE;
+        }
     }
 
     @Override
-    public void startTrace() {
-        if (!mA11yController.isAccessibilityTracingEnabled()) {
-            mA11yController.startTrace();
-            mService.scheduleUpdateClientsIfNeeded(mService.getCurrentUserState());
+    public boolean isA11yTracingEnabledForTypes(long typeIdFlags) {
+        synchronized (mA11yMSLock) {
+            return ((typeIdFlags & mEnabledLoggingFlags) != FLAGS_LOGGING_NONE);
         }
     }
 
     @Override
+    public int getTraceStateForAccessibilityManagerClientState() {
+        int state = 0x0;
+        synchronized (mA11yMSLock) {
+            if (isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION)) {
+                state |= STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED;
+            }
+            if (isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK)) {
+                state |= STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED;
+            }
+            if (isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_INTERACTION_CLIENT)) {
+                state |= STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED;
+            }
+            if (isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE)) {
+                state |= STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED;
+            }
+        }
+        return state;
+    }
+
+    @Override
+    public void startTrace(long loggingTypes) {
+        if (loggingTypes == FLAGS_LOGGING_NONE) {
+            // Ignore start none request
+            return;
+        }
+
+        synchronized (mA11yMSLock) {
+            long oldEnabled = mEnabledLoggingFlags;
+            mEnabledLoggingFlags = loggingTypes;
+
+            if (needToNotifyClients(oldEnabled)) {
+                mService.scheduleUpdateClientsIfNeededLocked(mService.getCurrentUserState());
+            }
+        }
+
+        mA11yController.startTrace(loggingTypes);
+    }
+
+    @Override
     public void stopTrace() {
-        if (mA11yController.isAccessibilityTracingEnabled()) {
+        boolean stop = false;
+        synchronized (mA11yMSLock) {
+            stop = isA11yTracingEnabled();
+
+            long oldEnabled = mEnabledLoggingFlags;
+            mEnabledLoggingFlags = FLAGS_LOGGING_NONE;
+
+            if (needToNotifyClients(oldEnabled)) {
+                mService.scheduleUpdateClientsIfNeededLocked(mService.getCurrentUserState());
+            }
+        }
+        if (stop) {
             mA11yController.stopTrace();
-            mService.scheduleUpdateClientsIfNeeded(mService.getCurrentUserState());
         }
     }
 
     @Override
-    public void logTrace(String where) {
-        logTrace(where, "");
+    public void logTrace(String where, long loggingTypes) {
+        logTrace(where, loggingTypes, "");
     }
 
     @Override
-    public void logTrace(String where, String callingParams) {
-        mA11yController.logTrace(where, callingParams, "".getBytes(),
-                Binder.getCallingUid(), Thread.currentThread().getStackTrace());
-    }
-
-    @Override
-    public void logTrace(long timestamp, String where, String callingParams, int processId,
-            long threadId, int callingUid, StackTraceElement[] callStack) {
-        if (mA11yController.isAccessibilityTracingEnabled()) {
-            mA11yController.logTrace(where, callingParams, "".getBytes(), callingUid, callStack,
-                    timestamp, processId, threadId);
+    public void logTrace(String where, long loggingTypes, String callingParams) {
+        if (isA11yTracingEnabledForTypes(loggingTypes)) {
+            mA11yController.logTrace(where, loggingTypes, callingParams, "".getBytes(),
+                    Binder.getCallingUid(), Thread.currentThread().getStackTrace(),
+                    new HashSet<String>(Arrays.asList("logTrace")));
         }
     }
 
-    int onShellCommand(String cmd) {
+    @Override
+    public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
+            int processId, long threadId, int callingUid, StackTraceElement[] callStack,
+            Set<String> ignoreElementList) {
+        if (isA11yTracingEnabledForTypes(loggingTypes)) {
+            mA11yController.logTrace(where, loggingTypes, callingParams, "".getBytes(), callingUid,
+                    callStack, timestamp, processId, threadId,
+                    ((ignoreElementList == null) ? new HashSet<String>() : ignoreElementList));
+        }
+    }
+
+    private boolean needToNotifyClients(long otherTypesEnabled) {
+        return (mEnabledLoggingFlags & FLAGS_ACCESSIBILITY_MANAGER_CLIENT_STATES)
+                != (otherTypesEnabled & FLAGS_ACCESSIBILITY_MANAGER_CLIENT_STATES);
+    }
+
+    int onShellCommand(String cmd, ShellCommand shell) {
         switch (cmd) {
             case "start-trace": {
-                startTrace();
+                String opt = shell.getNextOption();
+                if (opt == null) {
+                    startTrace(FLAGS_LOGGING_ALL);
+                    return 0;
+                }
+                List<String> types = new ArrayList<String>();
+                while (opt != null) {
+                    switch (opt) {
+                        case "-t": {
+                            String type = shell.getNextArg();
+                            while (type != null) {
+                                types.add(type);
+                                type = shell.getNextArg();
+                            }
+                            break;
+                        }
+                        default: {
+                            shell.getErrPrintWriter().println(
+                                    "Error: option not recognized " + opt);
+                            stopTrace();
+                            return -1;
+                        }
+                    }
+                    opt = shell.getNextOption();
+                }
+                long enabledTypes = AccessibilityTrace.getLoggingFlagsFromNames(types);
+                startTrace(enabledTypes);
                 return 0;
             }
             case "stop-trace": {
@@ -92,8 +217,29 @@
     }
 
     void onHelp(PrintWriter pw) {
-        pw.println("  start-trace");
-        pw.println("    Start the debug tracing.");
+        pw.println("  start-trace [-t LOGGING_TYPE [LOGGING_TYPE...]]");
+        pw.println("    Start the debug tracing. If no option is present, full trace will be");
+        pw.println("    generated. Options are:");
+        pw.println("      -t: Only generate tracing for the logging type(s) specified here.");
+        pw.println("          LOGGING_TYPE can be any one of below:");
+        pw.println("            IAccessibilityServiceConnection");
+        pw.println("            IAccessibilityServiceClient");
+        pw.println("            IAccessibilityManager");
+        pw.println("            IAccessibilityManagerClient");
+        pw.println("            IAccessibilityInteractionConnection");
+        pw.println("            IAccessibilityInteractionConnectionCallback");
+        pw.println("            IRemoteMagnificationAnimationCallback");
+        pw.println("            IWindowMagnificationConnection");
+        pw.println("            IWindowMagnificationConnectionCallback");
+        pw.println("            WindowManagerInternal");
+        pw.println("            WindowsForAccessibilityCallback");
+        pw.println("            MagnificationCallbacks");
+        pw.println("            InputFilter");
+        pw.println("            Gesture");
+        pw.println("            AccessibilityService");
+        pw.println("            PMBroadcastReceiver");
+        pw.println("            UserBroadcastReceiver");
+        pw.println("            FingerprintGesture");
         pw.println("  stop-trace");
         pw.println("    Stop the debug tracing.");
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 0fde0de..c70bf73 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -392,7 +392,7 @@
         return mBoundServices;
     }
 
-    int getClientStateLocked(boolean isUiAutomationRunning, boolean isTracingEnabled) {
+    int getClientStateLocked(boolean isUiAutomationRunning, int traceClientState) {
         int clientState = 0;
         final boolean a11yEnabled = isUiAutomationRunning
                 || isHandlingAccessibilityEventsLocked();
@@ -408,9 +408,9 @@
         if (mIsTextHighContrastEnabled) {
             clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
         }
-        if (isTracingEnabled) {
-            clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_TRACING_ENABLED;
-        }
+
+        clientState |= traceClientState;
+
         return clientState;
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index ff79469..b05dffe 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
 
@@ -69,6 +71,7 @@
     private final AccessibilityEventSender mAccessibilityEventSender;
     private final AccessibilitySecurityPolicy mSecurityPolicy;
     private final AccessibilityUserManager mAccessibilityUserManager;
+    private final AccessibilityTraceManager mTraceManager;
 
     // Connections and window tokens for cross-user windows
     private final SparseArray<RemoteAccessibilityConnection>
@@ -151,6 +154,10 @@
                 // In some cases, onWindowsForAccessibilityChanged will be called immediately in
                 // setWindowsForAccessibilityCallback. We'll lost windows if flag is false.
                 mTrackingWindows = true;
+                if (traceWMEnabled()) {
+                    logTraceWM("setWindowsForAccessibilityCallback",
+                            "displayId=" + mDisplayId + ";callback=" + this);
+                }
                 result = mWindowManagerInternal.setWindowsForAccessibilityCallback(
                         mDisplayId, this);
                 if (!result) {
@@ -167,6 +174,10 @@
          */
         void stopTrackingWindowsLocked() {
             if (mTrackingWindows) {
+                if (traceWMEnabled()) {
+                    logTraceWM("setWindowsForAccessibilityCallback",
+                            "displayId=" + mDisplayId + ";callback=null");
+                }
                 mWindowManagerInternal.setWindowsForAccessibilityCallback(
                         mDisplayId, null);
                 mTrackingWindows = false;
@@ -373,6 +384,20 @@
             }
         }
 
+        /**
+         * Called when the display is reparented and becomes an embedded
+         * display.
+         *
+         * @param embeddedDisplayId The embedded display Id.
+         */
+        @Override
+        public void onDisplayReparented(int embeddedDisplayId) {
+            // Removes the un-used window observer for the embedded display.
+            synchronized (mLock) {
+                mDisplayWindowsObservers.remove(embeddedDisplayId);
+            }
+        }
+
         private boolean shouldUpdateWindowsLocked(boolean forceSend,
                 @NonNull List<WindowInfo> windows) {
             if (forceSend) {
@@ -844,19 +869,21 @@
     }
 
     /**
-     * Constructor for AccessibilityManagerService.
+     * Constructor for AccessibilityWindowManager.
      */
     public AccessibilityWindowManager(@NonNull Object lock, @NonNull Handler handler,
             @NonNull WindowManagerInternal windowManagerInternal,
             @NonNull AccessibilityEventSender accessibilityEventSender,
             @NonNull AccessibilitySecurityPolicy securityPolicy,
-            @NonNull AccessibilityUserManager accessibilityUserManager) {
+            @NonNull AccessibilityUserManager accessibilityUserManager,
+            @NonNull AccessibilityTraceManager traceManager) {
         mLock = lock;
         mHandler = handler;
         mWindowManagerInternal = windowManagerInternal;
         mAccessibilityEventSender = accessibilityEventSender;
         mSecurityPolicy = securityPolicy;
         mAccessibilityUserManager = accessibilityUserManager;
+        mTraceManager = traceManager;
     }
 
     /**
@@ -957,6 +984,9 @@
         final int windowId;
         boolean shouldComputeWindows = false;
         final IBinder token = window.asBinder();
+        if (traceWMEnabled()) {
+            logTraceWM("getDisplayIdForWindow", "token=" + token);
+        }
         final int displayId = mWindowManagerInternal.getDisplayIdForWindow(token);
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
@@ -1003,9 +1033,15 @@
             registerIdLocked(leashToken, windowId);
         }
         if (shouldComputeWindows) {
+            if (traceWMEnabled()) {
+                logTraceWM("computeWindowsForAccessibility", "displayId=" + displayId);
+            }
             mWindowManagerInternal.computeWindowsForAccessibility(displayId);
         }
-
+        if (traceWMEnabled()) {
+            logTraceWM("setAccessibilityIdToSurfaceMetadata",
+                    "token=" + token + ";windowId=" + windowId);
+        }
         mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(token, windowId);
         return windowId;
     }
@@ -1139,6 +1175,10 @@
             mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
         }
         if (binder != null) {
+            if (traceWMEnabled()) {
+                logTraceWM("setAccessibilityIdToSurfaceMetadata", "token=" + binder
+                        + ";windowId=AccessibilityWindowInfo.UNDEFINED_WINDOW_ID");
+            }
             mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(
                     binder, AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
         }
@@ -1169,6 +1209,9 @@
      * @return The userId
      */
     public int getWindowOwnerUserId(@NonNull IBinder windowToken) {
+        if (traceWMEnabled()) {
+            logTraceWM("getWindowOwnerUserId", "token=" + windowToken);
+        }
         return mWindowManagerInternal.getWindowOwnerUserId(windowToken);
     }
 
@@ -1547,6 +1590,10 @@
         for (int i = 0; i < connectionList.size(); i++) {
             final RemoteAccessibilityConnection connection = connectionList.get(i);
             if (connection != null) {
+                if (traceIntConnEnabled()) {
+                    logTraceIntConn("notifyOutsideTouch");
+                }
+
                 try {
                     connection.getRemote().notifyOutsideTouch();
                 } catch (RemoteException re) {
@@ -1567,6 +1614,9 @@
      */
     public int getDisplayIdByUserIdAndWindowIdLocked(int userId, int windowId) {
         final IBinder windowToken = getWindowTokenForUserAndWindowIdLocked(userId, windowId);
+        if (traceWMEnabled()) {
+            logTraceWM("getDisplayIdForWindow", "token=" + windowToken);
+        }
         final int displayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
         return displayId;
     }
@@ -1595,6 +1645,9 @@
      * @return The input focused windowId, or -1 if not found
      */
     private int findFocusedWindowId(int userId) {
+        if (traceWMEnabled()) {
+            logTraceWM("getFocusedWindowToken", "");
+        }
         final IBinder token = mWindowManagerInternal.getFocusedWindowToken();
         synchronized (mLock) {
             return findWindowIdLocked(userId, token);
@@ -1644,6 +1697,9 @@
                 return;
             }
         }
+        if (traceIntConnEnabled()) {
+            logTraceIntConn("notifyOutsideTouch");
+        }
         try {
             connection.getRemote().clearAccessibilityFocus();
         } catch (RemoteException re) {
@@ -1666,6 +1722,25 @@
         return null;
     }
 
+    private boolean traceWMEnabled() {
+        return mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL);
+    }
+
+    private void logTraceWM(String methodName, String params) {
+        mTraceManager.logTrace("WindowManagerInternal." + methodName,
+                    FLAGS_WINDOW_MANAGER_INTERNAL, params);
+    }
+
+    private boolean traceIntConnEnabled() {
+        return mTraceManager.isA11yTracingEnabledForTypes(
+                FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION);
+    }
+
+    private void logTraceIntConn(String methodName) {
+        mTraceManager.logTrace(
+                    LOG_TAG + "." + methodName, FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION);
+    }
+
     /**
      * Associate the token of the embedded view hierarchy to the host view hierarchy.
      *
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index f5b0eb1..95f3560 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.accessibility;
 
+import android.accessibilityservice.AccessibilityTrace;
 import android.annotation.NonNull;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -56,6 +57,7 @@
 
     private static final String LOG_TAG = AutoclickController.class.getSimpleName();
 
+    private final AccessibilityTraceManager mTrace;
     private final Context mContext;
     private final int mUserId;
 
@@ -63,13 +65,18 @@
     private ClickScheduler mClickScheduler;
     private ClickDelayObserver mClickDelayObserver;
 
-    public AutoclickController(Context context, int userId) {
+    public AutoclickController(Context context, int userId, AccessibilityTraceManager trace) {
+        mTrace = trace;
         mContext = context;
         mUserId = userId;
     }
 
     @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mTrace.isA11yTracingEnabledForTypes(AccessibilityTrace.FLAGS_INPUT_FILTER)) {
+            mTrace.logTrace(LOG_TAG + ".onMotionEvent", AccessibilityTrace.FLAGS_INPUT_FILTER,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
             if (mClickScheduler == null) {
                 Handler handler = new Handler(mContext.getMainLooper());
@@ -89,6 +96,10 @@
 
     @Override
     public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (mTrace.isA11yTracingEnabledForTypes(AccessibilityTrace.FLAGS_INPUT_FILTER)) {
+            mTrace.logTrace(LOG_TAG + ".onKeyEvent", AccessibilityTrace.FLAGS_INPUT_FILTER,
+                    "event=" + event + ";policyFlags=" + policyFlags);
+        }
         if (mClickScheduler != null) {
             if (KeyEvent.isModifierKey(event.getKeyCode())) {
                 mClickScheduler.updateMetaState(event.getMetaState());
diff --git a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
index bc379c2..b8250c0 100644
--- a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
+++ b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER;
+
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
@@ -64,6 +66,10 @@
 
     @Override
     public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(FLAGS_INPUT_FILTER)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onKeyEvent",
+                    FLAGS_INPUT_FILTER, "event=" + event + ";policyFlags=" + policyFlags);
+        }
         /*
          * Certain keys have system-level behavior that affects accessibility services.
          * Let that behavior settle before handling the keys
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index ea2c7d2..0593f01 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -16,6 +16,7 @@
 
 package com.android.server.accessibility;
 
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.GestureDescription;
 import android.accessibilityservice.GestureDescription.GestureStep;
 import android.accessibilityservice.GestureDescription.TouchPoint;
@@ -68,6 +69,7 @@
     private final Handler mHandler;
     private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>();
 
+    private final AccessibilityTraceManager mTrace;
     private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture;
     private IntArray mSequencesInProgress = new IntArray(5);
     private boolean mIsDestroyed = false;
@@ -80,15 +82,17 @@
     /**
      * @param looper A looper on the main thread to use for dispatching new events
      */
-    public MotionEventInjector(Looper looper) {
+    public MotionEventInjector(Looper looper, AccessibilityTraceManager trace) {
         mHandler = new Handler(looper, this);
+        mTrace = trace;
     }
 
     /**
      * @param handler A handler to post messages. Exposes internal state for testing only.
      */
-    public MotionEventInjector(Handler handler) {
+    public MotionEventInjector(Handler handler, AccessibilityTraceManager trace) {
         mHandler = handler;
+        mTrace = trace;
     }
 
     /**
@@ -112,6 +116,12 @@
 
     @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mTrace.isA11yTracingEnabledForTypes(
+                AccessibilityTrace.FLAGS_INPUT_FILTER | AccessibilityTrace.FLAGS_GESTURE)) {
+            mTrace.logTrace(LOG_TAG + ".onMotionEvent",
+                    AccessibilityTrace.FLAGS_INPUT_FILTER | AccessibilityTrace.FLAGS_GESTURE,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         // MotionEventInjector would cancel any injected gesture when any MotionEvent arrives.
         // For user using an external device to control the pointer movement, it's almost
         // impossible to perform the gestures. Any slightly unintended movement results in the
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 9547280..6cd23fc 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -17,6 +17,7 @@
 package com.android.server.accessibility;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.annotation.Nullable;
 import android.app.UiAutomation;
@@ -269,6 +270,14 @@
                     // If the serviceInterface is null, the UiAutomation has been shut down on
                     // another thread.
                     if (serviceInterface != null) {
+                        if (mTrace.isA11yTracingEnabledForTypes(
+                                AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
+                            mTrace.logTrace("UiAutomationService.connectServiceUnknownThread",
+                                    AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT,
+                                    "serviceConnection=" + this + ";connectionId=" + mId
+                                    + "windowToken="
+                                    + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
+                        }
                         serviceInterface.init(this, mId,
                                 mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
                     }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index e1af2c4..f95de4e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility.gestures;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_GESTURE;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER;
 import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_HOVER_ENTER;
@@ -82,6 +84,7 @@
         implements GestureManifold.Listener {
 
     static final boolean DEBUG = false;
+    private static final long LOGGING_FLAGS = FLAGS_GESTURE | FLAGS_INPUT_FILTER;
 
     // Tag for logging received events.
     private static final String LOG_TAG = "TouchExplorer";
@@ -254,6 +257,10 @@
 
     @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onMotionEvent", LOGGING_FLAGS,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
             super.onMotionEvent(event, rawEvent, policyFlags);
             return;
@@ -303,6 +310,10 @@
 
     @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onAccessibilityEvent",
+                    LOGGING_FLAGS, "event=" + event);
+        }
         final int eventType = event.getEventType();
 
         if (eventType == TYPE_VIEW_HOVER_EXIT) {
@@ -341,6 +352,10 @@
 
     @Override
     public void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onDoubleTapAndHold", LOGGING_FLAGS,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         if (mDispatcher.longPressWithTouchEvents(event, policyFlags)) {
             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
             if (isSendMotionEventsEnabled()) {
@@ -357,6 +372,10 @@
 
     @Override
     public boolean onDoubleTap(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onDoubleTap", LOGGING_FLAGS,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         mAms.onTouchInteractionEnd();
         // Remove pending event deliveries.
         mSendHoverEnterAndMoveDelayed.cancel();
@@ -389,6 +408,9 @@
 
     @Override
     public boolean onGestureStarted() {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onGestureStarted", LOGGING_FLAGS);
+        }
         // We have to perform gesture detection, so
         // clear the current state and try to detect.
         mSendHoverEnterAndMoveDelayed.cancel();
@@ -402,6 +424,10 @@
 
     @Override
     public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onGestureCompleted",
+                    LOGGING_FLAGS, "event=" + gestureEvent);
+        }
         endGestureDetection(true);
         mSendTouchInteractionEndDelayed.cancel();
         dispatchGesture(gestureEvent);
@@ -410,6 +436,10 @@
 
     @Override
     public boolean onGestureCancelled(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mAms.getTraceManager().isA11yTracingEnabledForTypes(LOGGING_FLAGS)) {
+            mAms.getTraceManager().logTrace(LOG_TAG + ".onGestureCancelled", LOGGING_FLAGS,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         if (mState.isGestureDetecting()) {
             endGestureDetection(event.getActionMasked() == ACTION_UP);
             return true;
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 1f66bfd..218c851 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility.magnification;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
+
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
@@ -46,6 +48,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.util.Locale;
@@ -135,6 +138,10 @@
          */
         @GuardedBy("mLock")
         boolean register() {
+            if (traceEnabled()) {
+                logTrace("setMagnificationCallbacks",
+                        "displayID=" + mDisplayId + ";callback=" + this);
+            }
             mRegistered = mControllerCtx.getWindowManager().setMagnificationCallbacks(
                     mDisplayId, this);
             if (!mRegistered) {
@@ -142,6 +149,10 @@
                 return false;
             }
             mSpecAnimationBridge.setEnabled(true);
+            if (traceEnabled()) {
+                logTrace("getMagnificationRegion",
+                        "displayID=" + mDisplayId + ";region=" + mMagnificationRegion);
+            }
             // Obtain initial state.
             mControllerCtx.getWindowManager().getMagnificationRegion(
                     mDisplayId, mMagnificationRegion);
@@ -162,6 +173,10 @@
         void unregister(boolean delete) {
             if (mRegistered) {
                 mSpecAnimationBridge.setEnabled(false);
+                if (traceEnabled()) {
+                    logTrace("setMagnificationCallbacks",
+                            "displayID=" + mDisplayId + ";callback=null");
+                }
                 mControllerCtx.getWindowManager().setMagnificationCallbacks(
                         mDisplayId, null);
                 mMagnificationRegion.setEmpty();
@@ -431,6 +446,10 @@
         void setForceShowMagnifiableBounds(boolean show) {
             if (mRegistered) {
                 mForceShowMagnifiableBounds = show;
+                if (traceEnabled()) {
+                    logTrace("setForceShowMagnifiableBounds",
+                            "displayID=" + mDisplayId + ";show=" + show);
+                }
                 mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
                         mDisplayId, show);
             }
@@ -1255,6 +1274,16 @@
         }
     }
 
+    private boolean traceEnabled() {
+        return mControllerCtx.getTraceManager().isA11yTracingEnabledForTypes(
+                FLAGS_WINDOW_MANAGER_INTERNAL);
+    }
+
+    private void logTrace(String methodName, String params) {
+        mControllerCtx.getTraceManager().logTrace(
+                "WindowManagerInternal." + methodName, FLAGS_WINDOW_MANAGER_INTERNAL, params);
+    }
+
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -1320,6 +1349,13 @@
                     mEnabled = enabled;
                     if (!mEnabled) {
                         mSentMagnificationSpec.clear();
+                        if (mControllerCtx.getTraceManager().isA11yTracingEnabledForTypes(
+                                FLAGS_WINDOW_MANAGER_INTERNAL)) {
+                            mControllerCtx.getTraceManager().logTrace(
+                                    "WindowManagerInternal.setMagnificationSpec",
+                                    FLAGS_WINDOW_MANAGER_INTERNAL,
+                                    "displayID=" + mDisplayId + ";spec=" + mSentMagnificationSpec);
+                        }
                         mControllerCtx.getWindowManager().setMagnificationSpec(
                                 mDisplayId, mSentMagnificationSpec);
                     }
@@ -1367,6 +1403,13 @@
                 }
 
                 mSentMagnificationSpec.setTo(spec);
+                if (mControllerCtx.getTraceManager().isA11yTracingEnabledForTypes(
+                        FLAGS_WINDOW_MANAGER_INTERNAL)) {
+                    mControllerCtx.getTraceManager().logTrace(
+                            "WindowManagerInternal.setMagnificationSpec",
+                            FLAGS_WINDOW_MANAGER_INTERNAL,
+                            "displayID=" + mDisplayId + ";spec=" + mSentMagnificationSpec);
+                }
                 mControllerCtx.getWindowManager().setMagnificationSpec(
                         mDisplayId, mSentMagnificationSpec);
             }
@@ -1455,6 +1498,7 @@
     public static class ControllerContext {
         private final Context mContext;
         private final AccessibilityManagerService mAms;
+        private final AccessibilityTraceManager mTrace;
         private final WindowManagerInternal mWindowManager;
         private final Handler mHandler;
         private final Long mAnimationDuration;
@@ -1469,6 +1513,7 @@
                 long animationDuration) {
             mContext = context;
             mAms = ams;
+            mTrace = ams.getTraceManager();
             mWindowManager = windowManager;
             mHandler = handler;
             mAnimationDuration = animationDuration;
@@ -1491,6 +1536,14 @@
         }
 
         /**
+         * @return AccessibilityTraceManager
+         */
+        @NonNull
+        public AccessibilityTraceManager getTraceManager() {
+            return mTrace;
+        }
+
+        /**
          * @return WindowManagerInternal
          */
         @NonNull
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index f7d1b9a..c3d8d4c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -61,6 +61,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.gestures.GestureUtils;
 
 /**
@@ -142,12 +143,13 @@
 
     public FullScreenMagnificationGestureHandler(@UiContext Context context,
             FullScreenMagnificationController fullScreenMagnificationController,
+            AccessibilityTraceManager trace,
             Callback callback,
             boolean detectTripleTap,
             boolean detectShortcutTrigger,
             @NonNull WindowMagnificationPromptController promptController,
             int displayId) {
-        super(displayId, detectTripleTap, detectShortcutTrigger, callback);
+        super(displayId, detectTripleTap, detectShortcutTrigger, trace, callback);
         if (DEBUG_ALL) {
             Log.i(mLogTag,
                     "FullScreenMagnificationGestureHandler(detectTripleTap = " + detectTripleTap
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 f9aecd7..8aacafb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -411,8 +411,7 @@
         synchronized (mLock) {
             if (mWindowMagnificationMgr == null) {
                 mWindowMagnificationMgr = new WindowMagnificationManager(mContext,
-                        mAms.getCurrentUserIdLocked(),
-                        this);
+                        mAms.getCurrentUserIdLocked(), this, mAms.getTraceManager());
             }
             return mWindowMagnificationMgr;
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
index bbe40b6..19b3396 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
@@ -20,11 +20,13 @@
 import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_UP;
 
+import android.accessibilityservice.AccessibilityTrace;
 import android.annotation.NonNull;
 import android.util.Log;
 import android.util.Slog;
 import android.view.MotionEvent;
 
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.BaseEventStreamTransformation;
 
 import java.util.ArrayDeque;
@@ -99,14 +101,17 @@
         void onTripleTapped(int displayId, int mode);
     }
 
+    private final AccessibilityTraceManager mTrace;
     protected final Callback mCallback;
 
     protected MagnificationGestureHandler(int displayId, boolean detectTripleTap,
             boolean detectShortcutTrigger,
+            AccessibilityTraceManager trace,
             @NonNull Callback callback) {
         mDisplayId = displayId;
         mDetectTripleTap = detectTripleTap;
         mDetectShortcutTrigger = detectShortcutTrigger;
+        mTrace = trace;
         mCallback = callback;
 
         mDebugInputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
@@ -118,6 +123,12 @@
         if (DEBUG_ALL) {
             Slog.i(mLogTag, "onMotionEvent(" + event + ")");
         }
+        if (mTrace.isA11yTracingEnabledForTypes(
+                AccessibilityTrace.FLAGS_INPUT_FILTER | AccessibilityTrace.FLAGS_GESTURE)) {
+            mTrace.logTrace("MagnificationGestureHandler.onMotionEvent",
+                    AccessibilityTrace.FLAGS_INPUT_FILTER | AccessibilityTrace.FLAGS_GESTURE,
+                    "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags);
+        }
         if (DEBUG_EVENT_STREAM) {
             storeEventInto(mDebugInputEventHistory, event);
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
index 993027d..5277425 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapper.java
@@ -16,6 +16,9 @@
 
 package com.android.server.accessibility.magnification;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
 import static android.os.IBinder.DeathRecipient;
 
 import android.annotation.NonNull;
@@ -27,6 +30,8 @@
 import android.view.accessibility.IWindowMagnificationConnectionCallback;
 import android.view.accessibility.MagnificationAnimationCallback;
 
+import com.android.server.accessibility.AccessibilityTraceManager;
+
 /**
  * A wrapper of {@link IWindowMagnificationConnection}.
  */
@@ -36,9 +41,12 @@
     private static final String TAG = "WindowMagnificationConnectionWrapper";
 
     private final @NonNull IWindowMagnificationConnection mConnection;
+    private final @NonNull AccessibilityTraceManager mTrace;
 
-    WindowMagnificationConnectionWrapper(@NonNull IWindowMagnificationConnection connection) {
+    WindowMagnificationConnectionWrapper(@NonNull IWindowMagnificationConnection connection,
+            @NonNull AccessibilityTraceManager trace) {
         mConnection = connection;
+        mTrace = trace;
     }
 
     //Should not use this instance anymore after calling it.
@@ -52,9 +60,15 @@
 
     boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
             @Nullable MagnificationAnimationCallback callback) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".enableWindowMagnification",
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
+                    "displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
+                    + ";centerY=" + centerY + ";callback=" + callback);
+        }
         try {
             mConnection.enableWindowMagnification(displayId, scale, centerX, centerY,
-                    transformToRemoteCallback(callback));
+                    transformToRemoteCallback(callback, mTrace));
         } catch (RemoteException e) {
             if (DBG) {
                 Slog.e(TAG, "Error calling enableWindowMagnification()", e);
@@ -65,6 +79,10 @@
     }
 
     boolean setScale(int displayId, float scale) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".setScale", FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
+                    "displayId=" + displayId + ";scale=" + scale);
+        }
         try {
             mConnection.setScale(displayId, scale);
         } catch (RemoteException e) {
@@ -78,8 +96,14 @@
 
     boolean disableWindowMagnification(int displayId,
             @Nullable MagnificationAnimationCallback callback) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".disableWindowMagnification",
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
+                    "displayId=" + displayId + ";callback=" + callback);
+        }
         try {
-            mConnection.disableWindowMagnification(displayId, transformToRemoteCallback(callback));
+            mConnection.disableWindowMagnification(displayId,
+                    transformToRemoteCallback(callback, mTrace));
         } catch (RemoteException e) {
             if (DBG) {
                 Slog.e(TAG, "Error calling disableWindowMagnification()", e);
@@ -90,6 +114,10 @@
     }
 
     boolean moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".moveWindowMagnifier", FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
+                    "displayId=" + displayId + ";offsetX=" + offsetX + ";offsetY=" + offsetY);
+        }
         try {
             mConnection.moveWindowMagnifier(displayId, offsetX, offsetY);
         } catch (RemoteException e) {
@@ -102,6 +130,11 @@
     }
 
     boolean showMagnificationButton(int displayId, int magnificationMode) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".showMagnificationButton",
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
+                    "displayId=" + displayId + ";mode=" + magnificationMode);
+        }
         try {
             mConnection.showMagnificationButton(displayId, magnificationMode);
         } catch (RemoteException e) {
@@ -114,6 +147,10 @@
     }
 
     boolean removeMagnificationButton(int displayId) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".removeMagnificationButton",
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION, "displayId=" + displayId);
+        }
         try {
             mConnection.removeMagnificationButton(displayId);
         } catch (RemoteException e) {
@@ -126,6 +163,14 @@
     }
 
     boolean setConnectionCallback(IWindowMagnificationConnectionCallback connectionCallback) {
+        if (mTrace.isA11yTracingEnabledForTypes(
+                FLAGS_WINDOW_MAGNIFICATION_CONNECTION
+                | FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
+            mTrace.logTrace(TAG + ".setConnectionCallback",
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION
+                    | FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                    "callback=" + connectionCallback);
+        }
         try {
             mConnection.setConnectionCallback(connectionCallback);
         } catch (RemoteException e) {
@@ -139,25 +184,38 @@
 
     private static @Nullable
             IRemoteMagnificationAnimationCallback transformToRemoteCallback(
-            MagnificationAnimationCallback callback) {
+            MagnificationAnimationCallback callback, AccessibilityTraceManager trace) {
         if (callback == null) {
             return null;
         }
-        return new RemoteAnimationCallback(callback);
+        return new RemoteAnimationCallback(callback, trace);
     }
 
     private static class RemoteAnimationCallback extends
             IRemoteMagnificationAnimationCallback.Stub {
-
         private final MagnificationAnimationCallback mCallback;
+        private final AccessibilityTraceManager mTrace;
 
-        RemoteAnimationCallback(@NonNull MagnificationAnimationCallback callback) {
+        RemoteAnimationCallback(@NonNull MagnificationAnimationCallback callback,
+                               @NonNull AccessibilityTraceManager trace) {
             mCallback = callback;
+            mTrace = trace;
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK)) {
+                mTrace.logTrace("RemoteAnimationCallback.constructor",
+                        FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK, "callback=" + callback);
+            }
         }
 
         @Override
         public void onResult(boolean success) throws RemoteException {
             mCallback.onResult(success);
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK)) {
+                mTrace.logTrace("RemoteAnimationCallback.onResult",
+                        FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK, "success=" + success);
+            }
+
         }
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 4fb9a03..b26d364 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -34,6 +34,7 @@
 import android.view.MotionEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.EventStreamTransformation;
 import com.android.server.accessibility.gestures.MultiTap;
 import com.android.server.accessibility.gestures.MultiTapAndHold;
@@ -89,9 +90,10 @@
 
     public WindowMagnificationGestureHandler(@UiContext Context context,
             WindowMagnificationManager windowMagnificationMgr,
+            AccessibilityTraceManager trace,
             Callback callback,
             boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) {
-        super(displayId, detectTripleTap, detectShortcutTrigger, callback);
+        super(displayId, detectTripleTap, detectShortcutTrigger, trace, callback);
         if (DEBUG_ALL) {
             Slog.i(mLogTag,
                     "WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
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 938cb73..7a111d8 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -16,6 +16,9 @@
 
 package com.android.server.accessibility.magnification;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
@@ -39,6 +42,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 /**
@@ -111,11 +115,14 @@
     }
 
     private final Callback mCallback;
+    private final AccessibilityTraceManager mTrace;
 
-    public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback) {
+    public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback,
+            AccessibilityTraceManager trace) {
         mContext = context;
         mUserId = userId;
         mCallback = callback;
+        mTrace = trace;
     }
 
     /**
@@ -135,7 +142,7 @@
                 mConnectionWrapper = null;
             }
             if (connection != null) {
-                mConnectionWrapper = new WindowMagnificationConnectionWrapper(connection);
+                mConnectionWrapper = new WindowMagnificationConnectionWrapper(connection, mTrace);
             }
 
             if (mConnectionWrapper != null) {
@@ -197,7 +204,10 @@
                 }
             }
         }
-
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".requestWindowMagnificationConnection",
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION, "connect=" + connect);
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
             final StatusBarManagerInternal service = LocalServices.getService(
@@ -511,6 +521,12 @@
 
         @Override
         public void onWindowMagnifierBoundsChanged(int displayId, Rect bounds) {
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
+                mTrace.logTrace(TAG + "ConnectionCallback.onWindowMagnifierBoundsChanged",
+                        FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                        "displayId=" + displayId + ";bounds=" + bounds);
+            }
             synchronized (mLock) {
                 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
                 if (magnifier == null) {
@@ -527,11 +543,23 @@
         @Override
         public void onChangeMagnificationMode(int displayId, int magnificationMode)
                 throws RemoteException {
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
+                mTrace.logTrace(TAG + "ConnectionCallback.onChangeMagnificationMode",
+                        FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                        "displayId=" + displayId + ";mode=" + magnificationMode);
+            }
             //TODO: Uses this method to change the magnification mode on non-default display.
         }
 
         @Override
         public void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
+                mTrace.logTrace(TAG + "ConnectionCallback.onSourceBoundsChanged",
+                        FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                        "displayId=" + displayId + ";source=" + sourceBounds);
+            }
             synchronized (mLock) {
                 WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
                 if (magnifier == null) {
@@ -543,11 +571,23 @@
 
         @Override
         public void onPerformScaleAction(int displayId, float scale) {
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
+                mTrace.logTrace(TAG + "ConnectionCallback.onPerformScaleAction",
+                        FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                        "displayId=" + displayId + ";scale=" + scale);
+            }
             mCallback.onPerformScaleAction(displayId, scale);
         }
 
         @Override
         public void onAccessibilityActionPerformed(int displayId) {
+            if (mTrace.isA11yTracingEnabledForTypes(
+                    FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
+                mTrace.logTrace(TAG + "ConnectionCallback.onAccessibilityActionPerformed",
+                        FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
+                        "displayId=" + displayId);
+            }
             mCallback.onAccessibilityActionPerformed(displayId);
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
new file mode 100644
index 0000000..715697d
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.autofill;
+
+import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
+
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.ICancellationSignal;
+import android.os.RemoteException;
+import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
+import android.service.autofill.IFillCallback;
+import android.service.autofill.SaveInfo;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
+import android.view.inputmethod.InlineSuggestionsRequest;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Maintains a client suggestions session with the
+ * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}.
+ *
+ */
+final class ClientSuggestionsSession {
+
+    private static final String TAG = "ClientSuggestionsSession";
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS;
+
+    private final int mSessionId;
+    private final IAutoFillManagerClient mClient;
+    private final Handler mHandler;
+    private final ComponentName mComponentName;
+
+    private final RemoteFillService.FillServiceCallbacks mCallbacks;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private AndroidFuture<FillResponse> mPendingFillRequest;
+    @GuardedBy("mLock")
+    private int mPendingFillRequestId = INVALID_REQUEST_ID;
+
+    ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler,
+            ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) {
+        mSessionId = sessionId;
+        mClient = client;
+        mHandler = handler;
+        mComponentName = componentName;
+        mCallbacks = callbacks;
+    }
+
+    void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) {
+        final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
+        final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>();
+        final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>();
+
+        mHandler.post(() -> {
+            if (sVerbose) {
+                Slog.v(TAG, "calling onFillRequest() for id=" + requestId);
+            }
+
+            try {
+                mClient.requestFillFromClient(requestId, inlineRequest,
+                        new FillCallbackImpl(fillRequest, futureRef, cancellationSink));
+            } catch (RemoteException e) {
+                fillRequest.completeExceptionally(e);
+            }
+        });
+
+        fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
+        futureRef.set(fillRequest);
+
+        synchronized (mLock) {
+            mPendingFillRequest = fillRequest;
+            mPendingFillRequestId = requestId;
+        }
+
+        fillRequest.whenComplete((res, err) -> mHandler.post(() -> {
+            synchronized (mLock) {
+                mPendingFillRequest = null;
+                mPendingFillRequestId = INVALID_REQUEST_ID;
+            }
+            if (err == null) {
+                processAutofillId(res);
+                mCallbacks.onFillRequestSuccess(requestId, res,
+                        mComponentName.getPackageName(), flags);
+            } else {
+                Slog.e(TAG, "Error calling on  client fill request", err);
+                if (err instanceof TimeoutException) {
+                    dispatchCancellationSignal(cancellationSink.get());
+                    mCallbacks.onFillRequestTimeout(requestId);
+                } else if (err instanceof CancellationException) {
+                    dispatchCancellationSignal(cancellationSink.get());
+                } else {
+                    mCallbacks.onFillRequestFailure(requestId, err.getMessage());
+                }
+            }
+        }));
+    }
+
+    /**
+     * Gets the application info for the component.
+     */
+    @Nullable
+    static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) {
+        try {
+            ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo(
+                    comp.getPackageName(),
+                    PackageManager.GET_META_DATA,
+                    userId);
+            if (si != null) {
+                return si;
+            }
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    /**
+     * Gets the user-visible name of the application.
+     */
+    @Nullable
+    @GuardedBy("mLock")
+    static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) {
+        return appInfo == null ? null : appInfo.loadSafeLabel(
+                context.getPackageManager(), 0 /* do not ellipsize */,
+                TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM);
+    }
+
+    /**
+     * Gets the user-visible icon of the application.
+     */
+    @Nullable
+    @GuardedBy("mLock")
+    static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) {
+        return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager());
+    }
+
+    int cancelCurrentRequest() {
+        synchronized (mLock) {
+            return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
+                    ? mPendingFillRequestId
+                    : INVALID_REQUEST_ID;
+        }
+    }
+
+    /**
+     * The {@link AutofillId} which the client gets from its view is not contain the session id,
+     * but Autofill framework is using the {@link AutofillId} with a session id. So before using
+     * those ids in the Autofill framework, applies the current session id.
+     *
+     * @param res which response need to apply for a session id
+     */
+    private void processAutofillId(FillResponse res) {
+        if (res == null) {
+            return;
+        }
+
+        final List<Dataset> datasets = res.getDatasets();
+        if (datasets != null && !datasets.isEmpty()) {
+            for (int i = 0; i < datasets.size(); i++) {
+                final Dataset dataset = datasets.get(i);
+                if (dataset != null) {
+                    applySessionId(dataset.getFieldIds());
+                }
+            }
+        }
+
+        final SaveInfo saveInfo = res.getSaveInfo();
+        if (saveInfo != null) {
+            applySessionId(saveInfo.getOptionalIds());
+            applySessionId(saveInfo.getRequiredIds());
+            applySessionId(saveInfo.getSanitizerValues());
+            applySessionId(saveInfo.getTriggerId());
+        }
+    }
+
+    private void applySessionId(List<AutofillId> ids) {
+        if (ids == null || ids.isEmpty()) {
+            return;
+        }
+
+        for (int i = 0; i < ids.size(); i++) {
+            applySessionId(ids.get(i));
+        }
+    }
+
+    private void applySessionId(AutofillId[][] ids) {
+        if (ids == null) {
+            return;
+        }
+        for (int i = 0; i < ids.length; i++) {
+            applySessionId(ids[i]);
+        }
+    }
+
+    private void applySessionId(AutofillId[] ids) {
+        if (ids == null) {
+            return;
+        }
+        for (int i = 0; i < ids.length; i++) {
+            applySessionId(ids[i]);
+        }
+    }
+
+    private void applySessionId(AutofillId id) {
+        if (id == null) {
+            return;
+        }
+        id.setSessionId(mSessionId);
+    }
+
+    private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) {
+        if (signal == null) {
+            return;
+        }
+        try {
+            signal.cancel();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error requesting a cancellation", e);
+        }
+    }
+
+    private class FillCallbackImpl extends IFillCallback.Stub {
+        final AndroidFuture<FillResponse> mFillRequest;
+        final AtomicReference<AndroidFuture<FillResponse>> mFutureRef;
+        final AtomicReference<ICancellationSignal> mCancellationSink;
+
+        FillCallbackImpl(AndroidFuture<FillResponse> fillRequest,
+                AtomicReference<AndroidFuture<FillResponse>> futureRef,
+                AtomicReference<ICancellationSignal> cancellationSink) {
+            mFillRequest = fillRequest;
+            mFutureRef = futureRef;
+            mCancellationSink = cancellationSink;
+        }
+
+        @Override
+        public void onCancellable(ICancellationSignal cancellation) {
+            AndroidFuture<FillResponse> future = mFutureRef.get();
+            if (future != null && future.isCancelled()) {
+                dispatchCancellationSignal(cancellation);
+            } else {
+                mCancellationSink.set(cancellation);
+            }
+        }
+
+        @Override
+        public void onSuccess(FillResponse response) {
+            mFillRequest.complete(response);
+        }
+
+        @Override
+        public void onFailure(int requestId, CharSequence message) {
+            String errorMessage = message == null ? "" : String.valueOf(message);
+            mFillRequest.completeExceptionally(
+                    new RuntimeException(errorMessage));
+        }
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 078d908..11df871 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,6 +26,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
+import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
 
@@ -53,6 +54,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -346,6 +348,9 @@
      */
     private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
 
+    @Nullable
+    private ClientSuggestionsSession mClientSuggestionsSession;
+
     void onSwitchInputMethodLocked() {
         // One caveat is that for the case where the focus is on a field for which regular autofill
         // returns null, and augmented autofill is triggered,  and then the user switches the input
@@ -416,6 +421,10 @@
         /** Whether the current {@link FillResponse} is expired. */
         @GuardedBy("mLock")
         private boolean mExpiredResponse;
+
+        /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */
+        @GuardedBy("mLock")
+        private boolean mClientSuggestionsEnabled;
     }
 
     /**
@@ -441,13 +450,19 @@
                         return;
                     }
                     mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
-                    maybeRequestFillLocked();
+                    maybeRequestFillFromServiceLocked();
                     viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
                 }
             } : null;
         }
 
-        void maybeRequestFillLocked() {
+        void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) {
+            mPendingFillRequest = null;
+            mWaitForInlineRequest = inlineRequest != null;
+            mPendingInlineSuggestionsRequest = inlineRequest;
+        }
+
+        void maybeRequestFillFromServiceLocked() {
             if (mPendingFillRequest == null) {
                 return;
             }
@@ -457,9 +472,12 @@
                     return;
                 }
 
-                mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
-                        mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(),
-                        mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+                if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
+                    mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+                            mPendingFillRequest.getFillContexts(),
+                            mPendingFillRequest.getClientState(),
+                            mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+                }
             }
 
             mRemoteFillService.onFillRequest(mPendingFillRequest);
@@ -566,7 +584,7 @@
                         /*inlineSuggestionsRequest=*/null);
 
                 mPendingFillRequest = request;
-                maybeRequestFillLocked();
+                maybeRequestFillFromServiceLocked();
             }
 
             if (mActivityToken != null) {
@@ -728,30 +746,39 @@
     }
 
     /**
-     * Cancels the last request sent to the {@link #mRemoteFillService}.
+     * Cancels the last request sent to the {@link #mRemoteFillService} or the
+     * {@link #mClientSuggestionsSession}.
      */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
-        if (mRemoteFillService == null) {
-            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+        if (mRemoteFillService == null && mClientSuggestionsSession == null) {
+            wtf(null, "cancelCurrentRequestLocked() called without a remote service or a "
+                    + "client suggestions session.  mForAugmentedAutofillOnly: %s",
+                    mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
-        final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
-        // Remove the FillContext as there will never be a response for the service
-        if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
-            final int numContexts = mContexts.size();
+        if (mRemoteFillService != null) {
+            final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
-            // It is most likely the last context, hence search backwards
-            for (int i = numContexts - 1; i >= 0; i--) {
-                if (mContexts.get(i).getRequestId() == canceledRequest) {
-                    if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
-                    mContexts.remove(i);
-                    break;
+            // Remove the FillContext as there will never be a response for the service
+            if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) {
+                final int numContexts = mContexts.size();
+
+                // It is most likely the last context, hence search backwards
+                for (int i = numContexts - 1; i >= 0; i--) {
+                    if (mContexts.get(i).getRequestId() == canceledRequest) {
+                        if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest);
+                        mContexts.remove(i);
+                        break;
+                    }
                 }
             }
         }
+
+        if (mClientSuggestionsSession != null) {
+            mClientSuggestionsSession.cancelCurrentRequest();
+        }
     }
 
     private boolean isViewFocusedLocked(int flags) {
@@ -816,17 +843,30 @@
         // structure is taken. This causes only one fill request per burst of focus changes.
         cancelCurrentRequestLocked();
 
-        // Only ask IME to create inline suggestions request if Autofill provider supports it and
-        // the render service is available except the autofill is triggered manually and the view
-        // is also not focused.
+        // Only ask IME to create inline suggestions request when
+        // 1. Autofill provider supports it or client enabled client suggestions.
+        // 2. The render service is available.
+        // 3. The view is focused. (The view may not be focused if the autofill is triggered
+        //    manually.)
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if (mSessionFlags.mInlineSupportedByService
+        if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
                 && remoteRenderService != null
                 && isViewFocusedLocked(flags)) {
-            Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
-                    mAssistReceiver.newAutofillRequestLocked(viewState,
-                            /* isInlineRequest= */ true);
+            Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
+            if (mSessionFlags.mClientSuggestionsEnabled) {
+                final int finalRequestId = requestId;
+                inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> {
+                    // Using client suggestions
+                    synchronized (mLock) {
+                        onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest);
+                    }
+                    viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
+                };
+            } else {
+                inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(
+                        viewState, /* isInlineRequest= */ true);
+            }
             if (inlineSuggestionsRequestConsumer != null) {
                 final AutofillId focusedId = mCurrentViewId;
                 final int requestIdCopy = requestId;
@@ -842,11 +882,24 @@
                 );
                 viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
             }
+        } else if (mSessionFlags.mClientSuggestionsEnabled) {
+            // Request client suggestions for the dropdown mode
+            onClientFillRequestLocked(requestId, null);
         } else {
             mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false);
         }
 
+        if (mSessionFlags.mClientSuggestionsEnabled) {
+            // Using client suggestions, unnecessary request AssistStructure
+            return;
+        }
+
         // Now request the assist structure data.
+        requestAssistStructureLocked(requestId, flags);
+    }
+
+    @GuardedBy("mLock")
+    private void requestAssistStructureLocked(int requestId, int flags) {
         try {
             final Bundle receiverExtras = new Bundle();
             receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
@@ -895,10 +948,13 @@
         mComponentName = componentName;
         mCompatMode = compatMode;
         mSessionState = STATE_ACTIVE;
+
         synchronized (mLock) {
             mSessionFlags = new SessionFlags();
             mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
             mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
+            mSessionFlags.mClientSuggestionsEnabled =
+                    (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0;
             setClientLocked(client);
         }
 
@@ -1010,12 +1066,13 @@
                 if (requestLog != null) {
                     requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
                 }
-                processNullResponseLocked(requestId, requestFlags);
+                processNullResponseOrFallbackLocked(requestId, requestFlags);
                 return;
             }
 
             fieldClassificationIds = response.getFieldClassificationIds();
-            if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
+            if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null
+                    && !mService.isFieldClassificationEnabledLocked()) {
                 Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
                 processNullResponseLocked(requestId, requestFlags);
                 return;
@@ -1094,6 +1151,26 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private void processNullResponseOrFallbackLocked(int requestId, int flags) {
+        if (!mSessionFlags.mClientSuggestionsEnabled) {
+            processNullResponseLocked(requestId, flags);
+            return;
+        }
+
+        // fallback to the default platform password manager
+        mSessionFlags.mClientSuggestionsEnabled = false;
+
+        final InlineSuggestionsRequest inlineRequest =
+                (mLastInlineSuggestionsRequest != null
+                        && mLastInlineSuggestionsRequest.first == requestId)
+                        ? mLastInlineSuggestionsRequest.second : null;
+        mAssistReceiver.newAutofillRequestLocked(inlineRequest);
+        requestAssistStructureLocked(requestId,
+                flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
+        return;
+    }
+
     // FillServiceCallbacks
     @Override
     public void onFillRequestFailure(int requestId, @Nullable CharSequence message) {
@@ -3042,13 +3119,22 @@
             filterText = value.getTextValue().toString();
         }
 
-        final CharSequence serviceLabel;
-        final Drawable serviceIcon;
+        final CharSequence targetLabel;
+        final Drawable targetIcon;
         synchronized (mLock) {
-            serviceLabel = mService.getServiceLabelLocked();
-            serviceIcon = mService.getServiceIconLocked();
+            if (mSessionFlags.mClientSuggestionsEnabled) {
+                final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName,
+                        mService.getUserId());
+                targetLabel = ClientSuggestionsSession.getAppLabelLocked(
+                        mService.getMaster().getContext(), appInfo);
+                targetIcon = ClientSuggestionsSession.getAppIconLocked(
+                        mService.getMaster().getContext(), appInfo);
+            } else {
+                targetLabel = mService.getServiceLabelLocked();
+                targetIcon = mService.getServiceIconLocked();
+            }
         }
-        if (serviceLabel == null || serviceIcon == null) {
+        if (targetLabel == null || targetIcon == null) {
             wtf(null, "onFillReady(): no service label or icon");
             return;
         }
@@ -3068,7 +3154,7 @@
 
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mComponentName,
-                serviceLabel, serviceIcon, this, id, mCompatMode);
+                targetLabel, targetIcon, this, id, mCompatMode);
 
         mService.logDatasetShown(id, mClientState);
 
@@ -3115,6 +3201,17 @@
             return false;
         }
 
+        final InlineSuggestionsRequest request = inlineSuggestionsRequest.get();
+        if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported()
+                || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) {
+            if (sDebug) {
+                Slog.d(TAG, "Inline suggestions not supported for "
+                        + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service")
+                        + ". Falling back to dropdown.");
+            }
+            return false;
+        }
+
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
         if (remoteRenderService == null) {
@@ -3123,7 +3220,7 @@
         }
 
         final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
-                new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
+                new InlineFillUi.InlineFillUiInfo(request, focusedId,
                         filterText, remoteRenderService, userId, id);
         InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
                 new InlineFillUi.InlineSuggestionUiCallback() {
@@ -3725,6 +3822,25 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private void onClientFillRequestLocked(int requestId,
+            InlineSuggestionsRequest inlineSuggestionsRequest) {
+        if (mClientSuggestionsSession == null) {
+            mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler,
+                    mComponentName, this);
+        }
+
+        if (mContexts == null) {
+            mContexts = new ArrayList<>(1);
+        }
+
+        if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) {
+            inlineSuggestionsRequest = null;
+        }
+
+        mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags);
+    }
+
     /**
      * The result of checking whether to show the save dialog, when session can be saved.
      *
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 9ee0159..1a5d91c 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -4369,7 +4369,7 @@
             return OperationType.BACKUP;
         }
 
-        long oldCallingId = Binder.clearCallingIdentity();
+        final long oldCallingId = Binder.clearCallingIdentity();
         try {
             IBackupTransport transport = transportClient.connectOrThrow(
                     /* caller */ "BMS.getOperationTypeFromTransport");
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 906edb3..4af2e32 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -137,6 +137,8 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -145,6 +147,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.function.Function;
@@ -182,6 +185,11 @@
     private static final String XML_ATTR_TIME_APPROVED = "time_approved";
     private static final String XML_FILE_NAME = "companion_device_manager_associations.xml";
 
+    private static DateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    static {
+        sDateFormat.setTimeZone(TimeZone.getDefault());
+    }
+
     private final CompanionDeviceManagerImpl mImpl;
     private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>();
     private PowerWhitelistManager mPowerWhitelistManager;
@@ -641,7 +649,7 @@
                             association.getDeviceMacAddress(),
                             association.getPackageName(),
                             association.getDeviceProfile(),
-                            active, /* notifyOnDeviceNearby */
+                            active /* notifyOnDeviceNearby */,
                             association.getTimeApprovedMs());
                 } else {
                     return association;
@@ -720,12 +728,40 @@
             synchronized (mLock) {
                 for (UserInfo user : getAllUsers()) {
                     forEach(mCachedAssociations.get(user.id), a -> {
-                        fout.append("  ")
-                                .append("u").append("" + a.getUserId()).append(": ")
-                                .append(a.getPackageName()).append(" - ")
-                                .append(a.getDeviceMacAddress()).append('\n');
+                        fout.append("  ").append(a.toString()).append('\n');
                     });
                 }
+
+            }
+            fout.append("Currently Connected Devices:").append('\n');
+            for (int i = 0, size = mCurrentlyConnectedDevices.size(); i < size; i++) {
+                fout.append("  ").append(mCurrentlyConnectedDevices.get(i)).append('\n');
+            }
+
+            fout.append("Devices Last Nearby:").append('\n');
+            for (int i = 0, size = mDevicesLastNearby.size(); i < size; i++) {
+                String device = mDevicesLastNearby.keyAt(i);
+                Date time = mDevicesLastNearby.valueAt(i);
+                fout.append("  ").append(device).append(" -> ")
+                        .append(sDateFormat.format(time)).append('\n');
+            }
+
+            fout.append("Discovery Service State:").append('\n');
+            for (int i = 0, size = mServiceConnectors.size(); i < size; i++) {
+                int userId = mServiceConnectors.keyAt(i);
+                fout.append("  ")
+                        .append("u").append(Integer.toString(userId)).append(": ")
+                        .append(Objects.toString(mServiceConnectors.valueAt(i)))
+                        .append('\n');
+            }
+
+            fout.append("Device Listener Services State:").append('\n');
+            for (int i = 0, size = mDeviceListenerServiceConnectors.size(); i < size; i++) {
+                int userId = mDeviceListenerServiceConnectors.keyAt(i);
+                fout.append("  ")
+                        .append("u").append(Integer.toString(userId)).append(": ")
+                        .append(Objects.toString(mDeviceListenerServiceConnectors.valueAt(i)))
+                        .append('\n');
             }
         }
     }
@@ -776,7 +812,7 @@
                         + " for " + association
                         + " - profile still present in " + otherAssociationWithDeviceProfile);
             } else {
-                long identity = Binder.clearCallingIdentity();
+                final long identity = Binder.clearCallingIdentity();
                 try {
                     mRoleManager.removeRoleHolderAsUser(
                             association.getDeviceProfile(),
@@ -904,7 +940,7 @@
                 .getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
 
         Signature[] signatures = mPackageManagerInternal
-                .getPackage(packageName).getSigningDetails().signatures;
+                .getPackage(packageName).getSigningDetails().getSignatures();
         String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
 
         Set<String> sameOemPackageCerts =
@@ -1046,7 +1082,7 @@
     }
 
     private List<UserInfo> getAllUsers() {
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             return mUserManager.getUsers();
         } finally {
@@ -1062,7 +1098,7 @@
     }
 
     private Set<Association> getAllAssociations() {
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             ArraySet<Association> result = new ArraySet<>();
             for (UserInfo user : mUserManager.getAliveUsers()) {
@@ -1074,6 +1110,7 @@
         }
     }
 
+
     private Set<Association> getAllAssociations(
             int userId, @Nullable String packageFilter, @Nullable String addressFilter) {
         return CollectionUtils.filter(
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 55b982b..282b868 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -107,6 +107,7 @@
         ":display-device-config",
         ":display-layout-config",
         ":device-state-config",
+        ":guiconstants_aidl",
         "java/com/android/server/EventLogTags.logtags",
         "java/com/android/server/am/EventLogTags.logtags",
         "java/com/android/server/wm/EventLogTags.logtags",
@@ -152,7 +153,7 @@
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.rebootescrow-V1-java",
-        "android.hardware.soundtrigger-V2.3-java",
+        "android.hardware.soundtrigger-V2.4-java",
         "android.hardware.power.stats-V1-java",
         "android.hidl.manager-V1.2-java",
         "capture_state_listener-aidl-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index f7ddd29..a017f89 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.SigningDetails.CertCapabilities;
 import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.os.Bundle;
@@ -69,7 +70,6 @@
             PACKAGE_BROWSER,
             PACKAGE_SYSTEM_TEXT_CLASSIFIER,
             PACKAGE_PERMISSION_CONTROLLER,
-            PACKAGE_DOCUMENTER,
             PACKAGE_CONFIGURATOR,
             PACKAGE_INCIDENT_REPORT_APPROVER,
             PACKAGE_APP_PREDICTOR,
@@ -730,7 +730,7 @@
      * signing history for {@code serverUid} and with the {@code capability} specified.
      */
     public abstract boolean hasSignatureCapability(int serverUid, int clientUid,
-            @PackageParser.SigningDetails.CertCapabilities int capability);
+            @CertCapabilities int capability);
 
     /**
      * Get appIds of all available apps which specified android:sharedUserId in the manifest.
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 85ff2be..b4912bb 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -614,8 +614,12 @@
         }
         // waive WRITE_SECURE_SETTINGS permission check
         final long callingIdentity = Binder.clearCallingIdentity();
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, value);
-        Binder.restoreCallingIdentity(callingIdentity);
+        try {
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    Settings.Global.BLUETOOTH_ON, value);
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index a481a6a..f440ee8 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -61,7 +61,7 @@
     private static final String MDNS_TAG = "mDnsConnector";
 
     private static final boolean DBG = true;
-    private static final long CLEANUP_DELAY_MS = 3000;
+    private static final long CLEANUP_DELAY_MS = 10000;
 
     private final Context mContext;
     private final NsdSettings mNsdSettings;
@@ -94,19 +94,25 @@
             return NsdManager.nameOf(what);
         }
 
-        void maybeStartDaemon() {
+        private void maybeStartDaemon() {
             mDaemon.maybeStart();
             maybeScheduleStop();
         }
 
-        void maybeScheduleStop() {
+        private boolean isAnyRequestActive() {
+            return mIdToClientInfoMap.size() != 0;
+        }
+
+        private void scheduleStop() {
+            sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
+        }
+        private void maybeScheduleStop() {
             if (!isAnyRequestActive()) {
-                cancelStop();
-                sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
+                scheduleStop();
             }
         }
 
-        void cancelStop() {
+        private void cancelStop() {
             this.removeMessages(NsdManager.DAEMON_CLEANUP);
         }
 
@@ -164,11 +170,16 @@
                                 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
                                 break;
                         }
+
                         cInfo = mClients.get(msg.replyTo);
                         if (cInfo != null) {
                             cInfo.expungeAllRequests();
                             mClients.remove(msg.replyTo);
                         }
+                        //Last client
+                        if (mClients.size() == 0) {
+                            scheduleStop();
+                        }
                         break;
                     case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
                         AsyncChannel ac = new AsyncChannel();
@@ -235,7 +246,7 @@
             public void exit() {
                 // TODO: it is incorrect to stop the daemon without expunging all requests
                 // and sending error callbacks to clients.
-                maybeScheduleStop();
+                scheduleStop();
             }
 
             private boolean requestLimitReached(ClientInfo clientInfo) {
@@ -271,9 +282,6 @@
                         return NOT_HANDLED;
                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
                         return NOT_HANDLED;
-                }
-
-                switch (msg.what) {
                     case NsdManager.DISABLE:
                         //TODO: cleanup clients
                         transitionTo(mDisabledState);
@@ -531,10 +539,6 @@
        }
     }
 
-    private boolean isAnyRequestActive() {
-        return mIdToClientInfoMap.size() != 0;
-    }
-
     private String unescape(String s) {
         StringBuilder sb = new StringBuilder(s.length());
         for (int i = 0; i < s.length(); ++i) {
@@ -907,7 +911,6 @@
             }
             mClientIds.clear();
             mClientRequests.clear();
-            mNsdStateMachine.maybeScheduleStop();
         }
 
         // mClientIds is a sparse array of listener id -> mDnsClient id.  For a given mDnsClient id,
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index c07d669..370b283 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -348,7 +348,7 @@
                 return;
             }
 
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 onSensorUseStarted(uid, packageName, sensor);
             } finally {
@@ -642,7 +642,7 @@
                 mIndividualEnabled.put(userId, userIndividualEnabled);
 
                 if (!enable) {
-                    long token = Binder.clearCallingIdentity();
+                    final long token = Binder.clearCallingIdentity();
                     try {
                         // Remove any notifications prompting the user to disable sensory privacy
                         NotificationManager notificationManager =
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 69c2926..ec2f4aa 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -455,12 +455,6 @@
             "(?i)(^/storage/[^/]+/(?:([0-9]+)/)?Android/(?:data|media|obb|sandbox)/)([^/]+)(/.*)?");
 
 
-    /** Automotive device unlockes users before system boot complete and this requires special
-     * handling as vold reset can lead into race conditions. When this is set, all users unlocked
-     * in {@code UserManager} level are unlocked after vold reset.
-     */
-    private final boolean mIsAutomotive;
-
     private VolumeInfo findVolumeByIdOrThrow(String id) {
         synchronized (mLock) {
             final VolumeInfo vol = mVolumes.get(id);
@@ -1133,9 +1127,7 @@
                     mVold.onUserStarted(userId);
                     mStoraged.onUserStarted(userId);
                 }
-                if (mIsAutomotive) {
-                    restoreSystemUnlockedUsers(userManager, users, systemUnlockedUsers);
-                }
+                restoreSystemUnlockedUsers(userManager, users, systemUnlockedUsers);
                 mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
                 mStorageManagerInternal.onReset(mVold);
             } catch (Exception e) {
@@ -1219,13 +1211,11 @@
         // Record user as started so newly mounted volumes kick off events
         // correctly, then synthesize events for any already-mounted volumes.
         synchronized (mLock) {
-            if (mIsAutomotive) {
-                for (int unlockedUser : mSystemUnlockedUsers) {
-                    if (unlockedUser == userId) {
-                        // This can happen as restoreAllUnlockedUsers can double post the message.
-                        Log.i(TAG, "completeUnlockUser called for already unlocked user:" + userId);
-                        return;
-                    }
+            for (int unlockedUser : mSystemUnlockedUsers) {
+                if (unlockedUser == userId) {
+                    // This can happen as restoreAllUnlockedUsers can double post the message.
+                    Log.i(TAG, "completeUnlockUser called for already unlocked user:" + userId);
+                    return;
                 }
             }
             for (int i = 0; i < mVolumes.size(); i++) {
@@ -1922,9 +1912,6 @@
         if (WATCHDOG_ENABLE) {
             Watchdog.getInstance().addMonitor(this);
         }
-
-        mIsAutomotive = context.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_AUTOMOTIVE);
     }
 
     private void start() {
@@ -3461,48 +3448,6 @@
         }
     }
 
-    @Override
-    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
-            @StorageManager.AppIoBlockedReason int reason) {
-        enforceExternalStorageService();
-
-        mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
-    }
-
-    @Override
-    public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
-            @StorageManager.AppIoBlockedReason int reason) {
-        enforceExternalStorageService();
-
-        mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason);
-    }
-
-    @Override
-    public boolean isAppIoBlocked(String volumeUuid, int uid, int tid,
-            @StorageManager.AppIoBlockedReason int reason) {
-        return isAppIoBlocked(uid);
-    }
-
-
-    private boolean isAppIoBlocked(int uid) {
-        return mStorageSessionController.isAppIoBlocked(uid);
-    }
-
-    /**
-     * Enforces that the caller is the {@link ExternalStorageService}
-     *
-     * @throws SecurityException if the caller doesn't have the
-     * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the
-     * {@link ExternalStorageService}
-     */
-    private void enforceExternalStorageService() {
-        enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE);
-        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
-        if (callingAppId != mMediaStoreAuthorityAppId) {
-            throw new SecurityException("Only the ExternalStorageService is permitted");
-        }
-    }
-
     /**
      * Returns PendingIntent which can be used by Apps with MANAGE_EXTERNAL_STORAGE permission
      * to launch the manageSpaceActivity of the App specified by packageName.
@@ -3517,7 +3462,7 @@
         // We want to call the manageSpaceActivity as a SystemService and clear identity
         // of the calling App
         int originalUid = Binder.getCallingUidOrThrow();
-        long token = Binder.clearCallingIdentity();
+        final long token = Binder.clearCallingIdentity();
 
         try {
             ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0,
@@ -3550,6 +3495,46 @@
             Binder.restoreCallingIdentity(token);
         }
     }
+    
+    @Override
+    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) {
+        enforceExternalStorageService();
+
+        mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+    }
+
+    @Override
+    public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) {
+        enforceExternalStorageService();
+
+        mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+    }
+
+    @Override
+    public boolean isAppIoBlocked(String volumeUuid, int uid, int tid,
+            @StorageManager.AppIoBlockedReason int reason) {
+        return isAppIoBlocked(uid);
+    }
+
+
+    private boolean isAppIoBlocked(int uid) {
+        return mStorageSessionController.isAppIoBlocked(uid);
+    }
+
+    /**
+     * Enforces that the caller is the {@link ExternalStorageService}
+     *
+     * @throws SecurityException if the caller doesn't have the
+     * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the
+     * {@link ExternalStorageService}
+     */
+    private void enforceExternalStorageService() {
+        enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE);
+        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+        if (callingAppId != mMediaStoreAuthorityAppId) {
+            throw new SecurityException("Only the ExternalStorageService is permitted");
+        }
+    }
 
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
@@ -4599,7 +4584,6 @@
             pw.println();
             pw.println("Local unlocked users: " + mLocalUnlockedUsers);
             pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
-            pw.println("isAutomotive:" + mIsAutomotive);
         }
 
         synchronized (mObbMounts) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2a634eb..e587642 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -60,13 +60,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCacheListener;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails.CertCapabilities;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
+import android.database.sqlite.SQLiteFullException;
 import android.database.sqlite.SQLiteStatement;
 import android.os.Binder;
 import android.os.Bundle;
@@ -1833,6 +1834,11 @@
                                 + ", skipping since the account already exists");
                         return false;
                     }
+                    if (accounts.accountsDb.findAllDeAccounts().size() > 100) {
+                        Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+                                + ", skipping since more than 50 accounts on device exist");
+                        return false;
+                    }
                     long accountId = accounts.accountsDb.insertCeAccount(account, password);
                     if (accountId < 0) {
                         Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
@@ -4862,9 +4868,7 @@
                 int targetUid = targetActivityInfo.applicationInfo.uid;
                 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
                 if (!isExportedSystemActivity(targetActivityInfo)
-                        && !pmi.hasSignatureCapability(
-                                targetUid, authUid,
-                                PackageParser.SigningDetails.CertCapabilities.AUTH)) {
+                        && !pmi.hasSignatureCapability(targetUid, authUid, CertCapabilities.AUTH)) {
                     String pkgName = targetActivityInfo.packageName;
                     String activityName = targetActivityInfo.name;
                     String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that "
@@ -5236,7 +5240,7 @@
                     logStatement.bindLong(6, userDebugDbInsertionPoint);
                     try {
                         logStatement.execute();
-                    } catch (IllegalStateException e) {
+                    } catch (IllegalStateException | SQLiteFullException e) {
                         // Guard against crash, DB can already be closed
                         // since this statement is executed on a handler thread
                         Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId
@@ -5617,8 +5621,7 @@
                     return SIGNATURE_CHECK_UID_MATCH;
                 }
                 if (pmi.hasSignatureCapability(
-                        serviceInfo.uid, callingUid,
-                        PackageParser.SigningDetails.CertCapabilities.AUTH)) {
+                        serviceInfo.uid, callingUid, CertCapabilities.AUTH)) {
                     return SIGNATURE_CHECK_MATCH;
                 }
             }
@@ -5659,8 +5662,7 @@
         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
                 serviceInfos) {
             if (isOtherwisePermitted || pmi.hasSignatureCapability(
-                    serviceInfo.uid, callingUid,
-                    PackageParser.SigningDetails.CertCapabilities.AUTH)) {
+                    serviceInfo.uid, callingUid, CertCapabilities.AUTH)) {
                 managedAccountTypes.add(serviceInfo.type.type);
             }
         }
diff --git a/services/core/java/com/android/server/accounts/OWNERS b/services/core/java/com/android/server/accounts/OWNERS
index 8dcc04a..df1b4f4 100644
--- a/services/core/java/com/android/server/accounts/OWNERS
+++ b/services/core/java/com/android/server/accounts/OWNERS
@@ -1,9 +1 @@
-carlosvaldivia@google.com
-dementyev@google.com
-sandrakwan@google.com
-hackbod@google.com
-svetoslavganov@google.com
-fkupolov@google.com
-yamasani@google.com
-omakoto@google.com
-
+include /core/java/android/accounts/OWNERS
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3b0a68c..119e487 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3290,13 +3290,19 @@
 
         final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64);
         final long now = System.currentTimeMillis();
-        Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
-        for (int i = 0; i < files.length; ++i) {
-            if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) {
-                if (!files[i].delete()) {
-                    Slog.w(TAG, "Unable to prune stale trace file: " + files[i]);
+        try {
+            Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
+            for (int i = 0; i < files.length; ++i) {
+                if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) {
+                    if (!files[i].delete()) {
+                        Slog.w(TAG, "Unable to prune stale trace file: " + files[i]);
+                    }
                 }
             }
+        } catch (IllegalArgumentException e) {
+            // The modification times changed while we were sorting. Bail...
+            // https://issuetracker.google.com/169836837
+            Slog.w(TAG, "tombstone modification times changed while sorting; not pruning", e);
         }
     }
 
@@ -8341,11 +8347,13 @@
                 if (lines > 0) {
                     sb.append("\n");
 
-                    // Merge several logcat streams, and take the last N lines
                     InputStreamReader input = null;
                     try {
                         java.lang.Process logcat = new ProcessBuilder(
-                                "/system/bin/timeout", "-k", "15s", "10s",
+                                // Time out after 10s, but kill logcat with SEGV
+                                // so we can investigate why it didn't finish.
+                                "/system/bin/timeout", "-s", "SEGV", "10s",
+                                // Merge several logcat streams, and take the last N lines.
                                 "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system",
                                 "-b", "main", "-b", "crash", "-t", String.valueOf(lines))
                                         .redirectErrorStream(true).start();
@@ -12084,6 +12092,31 @@
             Slog.w(TAG, "Unable to bind backup agent for " + packageName);
             return false;
         }
+        if (app.backupAgentName != null) {
+            final ComponentName backupAgentName = new ComponentName(
+                    app.packageName, app.backupAgentName);
+            int enableState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+            try {
+                enableState = pm.getComponentEnabledSetting(backupAgentName, instantiatedUserId);
+            } catch (RemoteException e) {
+                // can't happen; package manager is process-local
+            }
+            switch (enableState) {
+                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
+                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
+                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
+                    Slog.w(TAG, "Unable to bind backup agent for " + backupAgentName
+                            + ", the backup agent component is disabled.");
+                    return false;
+
+                case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+                case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+                default:
+                    // Since there's no way to declare a backup agent disabled in the manifest,
+                    // assume the case COMPONENT_ENABLED_STATE_DEFAULT to be enabled.
+                    break;
+            }
+        }
 
         int oldBackupUid;
         int newBackupUid;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 7d9d789..c5b69c6 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -482,9 +482,9 @@
         final PowerManagerInternal powerMgr = LocalServices.getService(PowerManagerInternal.class);
         powerMgr.registerLowPowerModeObserver(this);
         synchronized (mStats) {
-            mStats.notePowerSaveModeLocked(
+            mStats.notePowerSaveModeLockedInit(
                     powerMgr.getLowPowerState(ServiceType.BATTERY_STATS).batterySaverEnabled,
-                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis(), true);
+                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
         }
         (new WakeupReasonThread()).start();
     }
@@ -527,7 +527,7 @@
             mHandler.post(() -> {
                 synchronized (mStats) {
                     mStats.notePowerSaveModeLocked(result.batterySaverEnabled,
-                            elapsedRealtime, uptime, false);
+                            elapsedRealtime, uptime);
                 }
             });
         }
diff --git a/services/core/java/com/android/server/am/CacheOomRanker.java b/services/core/java/com/android/server/am/CacheOomRanker.java
index 50278fd..1ead7e3 100644
--- a/services/core/java/com/android/server/am/CacheOomRanker.java
+++ b/services/core/java/com/android/server/am/CacheOomRanker.java
@@ -38,16 +38,25 @@
     private static final boolean DEFAULT_USE_OOM_RE_RANKING = false;
     @VisibleForTesting
     static final String KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK = "oom_re_ranking_number_to_re_rank";
-    @VisibleForTesting static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8;
+    @VisibleForTesting
+    static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8;
+    @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS =
+            "oom_re_ranking_preserve_top_n_apps";
+    @VisibleForTesting
+    static final int DEFAULT_PRESERVE_TOP_N_APPS = 3;
     @VisibleForTesting
     static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight";
-    @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f;
+    @VisibleForTesting
+    static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f;
     @VisibleForTesting
     static final String KEY_OOM_RE_RANKING_USES_WEIGHT = "oom_re_ranking_uses_weight";
-    @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f;
+    @VisibleForTesting
+    static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f;
     @VisibleForTesting
     static final String KEY_OOM_RE_RANKING_RSS_WEIGHT = "oom_re_ranking_rss_weight";
-    @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f;
+    @VisibleForTesting
+    static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f;
 
     private static final Comparator<RankedProcessRecord> SCORED_PROCESS_RECORD_COMPARATOR =
             new ScoreComparator();
@@ -66,15 +75,21 @@
 
     @GuardedBy("mPhenotypeFlagLock")
     private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting
+    int mPreserveTopNApps = DEFAULT_PRESERVE_TOP_N_APPS;
     // Weight to apply to the LRU ordering.
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT;
+    @VisibleForTesting
+    float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT;
     // Weight to apply to the ordering by number of times the process has been added to the cache.
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT;
+    @VisibleForTesting
+    float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT;
     // Weight to apply to the ordering by RSS used by the processes.
     @GuardedBy("mPhenotypeFlagLock")
-    @VisibleForTesting float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT;
+    @VisibleForTesting
+    float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT;
 
     // Positions to replace in the lru list.
     @GuardedBy("mPhenotypeFlagLock")
@@ -93,6 +108,8 @@
                                 updateUseOomReranking();
                             } else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) {
                                 updateNumberToReRank();
+                            } else if (KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS.equals(name)) {
+                                updatePreserveTopNApps();
                             } else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) {
                                 updateLruWeight();
                             } else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) {
@@ -160,6 +177,19 @@
     }
 
     @GuardedBy("mPhenotypeFlagLock")
+    private void updatePreserveTopNApps() {
+        int preserveTopNApps = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS, DEFAULT_PRESERVE_TOP_N_APPS);
+        if (preserveTopNApps < 0) {
+            Slog.w(OomAdjuster.TAG,
+                    "Found negative value for preserveTopNApps, setting to default: "
+                            + preserveTopNApps);
+            preserveTopNApps = DEFAULT_PRESERVE_TOP_N_APPS;
+        }
+        mPreserveTopNApps = preserveTopNApps;
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
     private void updateLruWeight() {
         mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 KEY_OOM_RE_RANKING_LRU_WEIGHT, DEFAULT_OOM_RE_RANKING_LRU_WEIGHT);
@@ -183,6 +213,33 @@
      */
     @GuardedBy({"mService", "mProcLock"})
     void reRankLruCachedAppsLSP(ArrayList<ProcessRecord> lruList, int lruProcessServiceStart) {
+        // The lruList is a list of processes ordered by how recently they were used. The
+        // least-recently-used apps are at the beginning of the list. We keep track of two
+        // indices in the lruList:
+        //
+        // getNumberToReRank=5, preserveTopNApps=3, lruProcessServiceStart=7,
+        // lruList=
+        //   0: app A       ^
+        //   1: app B       | These apps are re-ranked, as they are the first five apps (see
+        //   2: app C       | getNumberToReRank), excluding...
+        //   3: app D       v
+        //   4: app E       ^
+        //   5: app F       | The three most-recently-used apps in the cache (see preserveTopNApps).
+        //   6: app G       v
+        //   7: service A   ^
+        //   8: service B   | Everything beyond lruProcessServiceStart is ignored, as these aren't
+        //   9: service C   | apps.
+        //  10: activity A  |
+        //      ...         |
+        //
+        // `numProcessesEvaluated` moves across the apps (indices 0-6) or until we've found enough
+        // apps to re-rank, and made sure none of them are in the top `preserveTopNApps` apps.
+        // Re-ranked apps are copied into `scoredProcessRecords`, where the re-ranking calculation
+        // happens.
+        //
+        // Note that some apps in the `lruList` can be skipped, if they don't pass
+        //`appCanBeReRanked`.
+
         float lruWeight;
         float usesWeight;
         float rssWeight;
@@ -202,52 +259,67 @@
             return;
         }
 
+        int numProcessesEvaluated = 0;
         // Collect the least recently used processes to re-rank, only rank cached
         // processes further down the list than mLruProcessServiceStart.
-        int cachedProcessPos = 0;
-        for (int i = 0; i < lruProcessServiceStart
-                && cachedProcessPos < scoredProcessRecords.length; ++i) {
-            ProcessRecord app = lruList.get(i);
+        int numProcessesReRanked = 0;
+        while (numProcessesEvaluated < lruProcessServiceStart
+                && numProcessesReRanked < scoredProcessRecords.length) {
+            ProcessRecord process = lruList.get(numProcessesEvaluated);
             // Processes that will be assigned a cached oom adj score.
-            if (!app.isKilledByAm() && app.getThread() != null && app.mState.getCurAdj()
-                    >= ProcessList.UNKNOWN_ADJ) {
-                scoredProcessRecords[cachedProcessPos].proc = app;
-                scoredProcessRecords[cachedProcessPos].score = 0.0f;
-                lruPositions[cachedProcessPos] = i;
-                ++cachedProcessPos;
+            if (appCanBeReRanked(process)) {
+                scoredProcessRecords[numProcessesReRanked].proc = process;
+                scoredProcessRecords[numProcessesReRanked].score = 0.0f;
+                lruPositions[numProcessesReRanked] = numProcessesEvaluated;
+                ++numProcessesReRanked;
             }
+            ++numProcessesEvaluated;
         }
 
-        // TODO maybe ensure a certain number above this in the cache before re-ranking.
-        if (cachedProcessPos < scoredProcessRecords.length)  {
-            // Ignore we don't have enough processes to worry about re-ranking.
-            return;
+        // Count how many apps we're not re-ranking (up to mPreserveTopNApps).
+        int numProcessesNotReRanked = 0;
+        while (numProcessesEvaluated < lruProcessServiceStart
+                && numProcessesNotReRanked < mPreserveTopNApps) {
+            ProcessRecord process = lruList.get(numProcessesEvaluated);
+            if (appCanBeReRanked(process)) {
+                numProcessesNotReRanked++;
+            }
+            numProcessesEvaluated++;
+        }
+        // Exclude the top `mPreserveTopNApps` apps from re-ranking.
+        if (numProcessesNotReRanked < mPreserveTopNApps) {
+            numProcessesReRanked -= mPreserveTopNApps - numProcessesNotReRanked;
+            if (numProcessesReRanked < 0) {
+                numProcessesReRanked = 0;
+            }
         }
 
         // Add scores for each of the weighted features we want to rank based on.
         if (lruWeight > 0.0f) {
             // This doesn't use the LRU list ordering as after the first re-ranking
             // that will no longer be lru.
-            Arrays.sort(scoredProcessRecords, LAST_ACTIVITY_TIME_COMPARATOR);
+            Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked,
+                    LAST_ACTIVITY_TIME_COMPARATOR);
             addToScore(scoredProcessRecords, lruWeight);
         }
         if (rssWeight > 0.0f) {
             synchronized (mService.mAppProfiler.mProfilerLock) {
-                Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR);
+                Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, LAST_RSS_COMPARATOR);
             }
             addToScore(scoredProcessRecords, rssWeight);
         }
         if (usesWeight > 0.0f) {
-            Arrays.sort(scoredProcessRecords, CACHE_USE_COMPARATOR);
+            Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked, CACHE_USE_COMPARATOR);
             addToScore(scoredProcessRecords, usesWeight);
         }
 
         // Re-rank by the new combined score.
-        Arrays.sort(scoredProcessRecords, SCORED_PROCESS_RECORD_COMPARATOR);
+        Arrays.sort(scoredProcessRecords, 0, numProcessesReRanked,
+                SCORED_PROCESS_RECORD_COMPARATOR);
 
         if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
             boolean printedHeader = false;
-            for (int i = 0; i < scoredProcessRecords.length; ++i) {
+            for (int i = 0; i < numProcessesReRanked; ++i) {
                 if (scoredProcessRecords[i].proc.getPid()
                         != lruList.get(lruPositions[i]).getPid()) {
                     if (!printedHeader) {
@@ -260,12 +332,18 @@
             }
         }
 
-        for (int i = 0; i < scoredProcessRecords.length; ++i) {
+        for (int i = 0; i < numProcessesReRanked; ++i) {
             lruList.set(lruPositions[i], scoredProcessRecords[i].proc);
             scoredProcessRecords[i].proc = null;
         }
     }
 
+    private static boolean appCanBeReRanked(ProcessRecord process) {
+        return !process.isKilledByAm()
+                && process.getThread() != null
+                && process.mState.getCurAdj() >= ProcessList.UNKNOWN_ADJ;
+    }
+
     private static void addToScore(RankedProcessRecord[] scores, float weight) {
         for (int i = 1; i < scores.length; ++i) {
             scores[i].score += i * weight;
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index b325ea3..5a1a6b4 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -93,8 +93,6 @@
         sGlobalSettingToTypeMap.put(
                 Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
         sGlobalSettingToTypeMap.put(
-                Settings.Global.ANGLE_ALLOWLIST, String.class);
-        sGlobalSettingToTypeMap.put(
                 Settings.Global.ANGLE_EGL_FEATURES, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index e022e97..52ab4c8 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -92,6 +92,7 @@
         DeviceConfig.NAMESPACE_STATSD_NATIVE,
         DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+        DeviceConfig.NAMESPACE_SWCODEC_NATIVE,
         DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
     };
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba3e1fb..45d31f3 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -590,7 +590,11 @@
                 Slogf.w(TAG, "User key got locked unexpectedly, leaving user locked.");
                 return;
             }
+
+            final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+            t.traceBegin("UM.onBeforeUnlockUser-" + userId);
             mInjector.getUserManager().onBeforeUnlockUser(userId);
+            t.traceEnd();
             synchronized (mLock) {
                 // Do not proceed if unexpected state
                 if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
@@ -1683,7 +1687,11 @@
             return false;
         }
 
-        if (!finishUserUnlocking(uss)) {
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("finishUserUnlocking-" + userId);
+        final boolean finishUserUnlockingResult = finishUserUnlocking(uss);
+        t.traceEnd();
+        if (!finishUserUnlockingResult) {
             notifyFinished(userId, listener);
             return false;
         }
@@ -1849,6 +1857,9 @@
     }
 
     void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) {
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("dispatchUserSwitch-" + oldUserId + "-to-" + newUserId);
+
         EventLog.writeEvent(EventLogTags.UC_DISPATCH_USER_SWITCH, oldUserId, newUserId);
 
         final int observerCount = mUserSwitchObservers.beginBroadcast();
@@ -1901,6 +1912,7 @@
             }
         }
         mUserSwitchObservers.finishBroadcast();
+        t.traceEnd(); // end dispatchUserSwitch-
     }
 
     @GuardedBy("mLock")
@@ -1912,16 +1924,23 @@
     }
 
     void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("continueUserSwitch-" + oldUserId + "-to-" + newUserId);
+
         EventLog.writeEvent(EventLogTags.UC_CONTINUE_USER_SWITCH, oldUserId, newUserId);
 
         if (isUserSwitchUiEnabled()) {
+            t.traceBegin("stopFreezingScreen");
             mInjector.getWindowManager().stopFreezingScreen();
+            t.traceEnd();
         }
         uss.switching = false;
         mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
         mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
         stopGuestOrEphemeralUserIfBackground(oldUserId);
         stopBackgroundUsersOnSwitchIfEnforced(oldUserId);
+
+        t.traceEnd(); // end continueUserSwitch
     }
 
     private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
@@ -2670,7 +2689,11 @@
                         USER_LIFECYCLE_EVENT_STATE_FINISH);
                 logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKED_USER,
                         USER_LIFECYCLE_EVENT_STATE_BEGIN);
+
+                final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+                t.traceBegin("finishUserUnlocked-" + userId);
                 finishUserUnlocked((UserState) msg.obj);
+                t.traceEnd();
                 break;
             case USER_UNLOCKED_MSG:
                 mInjector.getSystemServiceManager().onUserUnlocked(msg.arg1);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 136916a..5210099 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2585,14 +2585,6 @@
         }
     }
 
-    /** @see AudioManager#adjustVolume(int, int) */
-    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
-            String callingPackage, String caller) {
-        adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
-                caller, Binder.getCallingUid(), callingHasAudioSettingsPermission(),
-                VOL_ADJUST_NORMAL);
-    }
-
     public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
         mNavigationRepeatSoundEffectsEnabled = enabled;
     }
@@ -2615,6 +2607,7 @@
         return mHomeSoundEffectEnabled;
     }
 
+    /** All callers come from platform apps/system server, so no attribution tag is needed */
     private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
             String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
             int keyEventMode) {
@@ -2690,7 +2683,7 @@
         }
 
         adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid,
-                hasModifyAudioSettings, keyEventMode);
+                null, hasModifyAudioSettings, keyEventMode);
     }
 
     private boolean notifyExternalVolumeController(int direction) {
@@ -2708,10 +2701,16 @@
         return true;
     }
 
-    /** @see AudioManager#adjustStreamVolume(int, int, int)
-     * Part of service interface, check permissions here */
+    /** Retain API for unsupported app usage */
     public void adjustStreamVolume(int streamType, int direction, int flags,
             String callingPackage) {
+        adjustStreamVolumeWithAttribution(streamType, direction, flags, callingPackage, null);
+    }
+
+    /** @see AudioManager#adjustStreamVolume(int, int, int)
+     * Part of service interface, check permissions here */
+    public void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags,
+            String callingPackage, String attributionTag) {
         if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
             Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
                     + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
@@ -2721,13 +2720,13 @@
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
                 direction/*val1*/, flags/*val2*/, callingPackage));
         adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
-                Binder.getCallingUid(), callingHasAudioSettingsPermission(),
+                Binder.getCallingUid(), attributionTag, callingHasAudioSettingsPermission(),
                 VOL_ADJUST_NORMAL);
     }
 
     protected void adjustStreamVolume(int streamType, int direction, int flags,
-            String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
-            int keyEventMode) {
+            String callingPackage, String caller, int uid, String attributionTag,
+            boolean hasModifyAudioSettings, int keyEventMode) {
         if (mUseFixedVolume) {
             return;
         }
@@ -2792,8 +2791,8 @@
         if (uid == android.os.Process.SYSTEM_UID) {
             uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
         }
-        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
+        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid,
+                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
             return;
         }
 
@@ -3159,7 +3158,7 @@
 
     /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */
     public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags,
-                                            String callingPackage) {
+            String callingPackage, String attributionTag) {
         enforceModifyAudioRoutingPermission();
         Objects.requireNonNull(attr, "attr must not be null");
         final int volumeGroup = getVolumeGroupIdForAttributes(attr);
@@ -3184,7 +3183,7 @@
                 continue;
             }
             setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage,
-                            Binder.getCallingUid(), true /*hasModifyAudioSettings*/);
+                    attributionTag, Binder.getCallingUid(), true /*hasModifyAudioSettings*/);
         }
     }
 
@@ -3226,9 +3225,15 @@
         return AudioSystem.getMinVolumeIndexForAttributes(attr);
     }
 
+    /** Retain API for unsupported app usage */
+    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
+        setStreamVolumeWithAttribution(streamType, index, flags, callingPackage, null);
+    }
+
     /** @see AudioManager#setStreamVolume(int, int, int)
      * Part of service interface, check permissions here */
-    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
+    public void setStreamVolumeWithAttribution(int streamType, int index, int flags,
+            String callingPackage, String attributionTag) {
         if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
             Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
                     + " CHANGE_ACCESSIBILITY_VOLUME  callingPackage=" + callingPackage);
@@ -3254,7 +3259,7 @@
         sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
                 index/*val1*/, flags/*val2*/, callingPackage));
         setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
-                Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission());
+                attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission());
     }
 
     private boolean canChangeAccessibilityVolume() {
@@ -3489,7 +3494,8 @@
     }
 
     private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
-            String caller, int uid, boolean hasModifyAudioSettings) {
+            String caller, String attributionTag, int uid,
+            boolean hasModifyAudioSettings) {
         if (DEBUG_VOL) {
             Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
                     + ", calling=" + callingPackage + ")");
@@ -3516,8 +3522,8 @@
         if (uid == android.os.Process.SYSTEM_UID) {
             uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
         }
-        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
+        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid,
+                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
             return;
         }
 
@@ -3603,7 +3609,7 @@
         }
         // The default volume group is the one hosted by default product strategy, i.e.
         // supporting Default Attributes
-        return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes);
+        return getVolumeGroupIdForAttributesInt(AudioProductStrategy.getDefaultAttributes());
     }
 
     private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) {
@@ -3945,15 +3951,15 @@
     }
 
     private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
-            int userId) {
+            int userId, String attributionTag) {
         // If we are being called by the system check for user we are going to change
         // so we handle user restrictions correctly.
         if (uid == android.os.Process.SYSTEM_UID) {
             uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
         }
         // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
-        if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
+        if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid,
+                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
             return;
         }
         if (userId != UserHandle.getCallingUserId() &&
@@ -3995,10 +4001,12 @@
         return AudioSystem.getMasterMute();
     }
 
-    public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
+    /** @see AudioManager#setMasterMute(boolean, int) */
+    public void setMasterMute(boolean mute, int flags, String callingPackage, int userId,
+            String attributionTag) {
         enforceModifyAudioRoutingPermission();
-        setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
-                userId);
+        setMasterMuteInternal(mute, flags, callingPackage,
+                Binder.getCallingUid(), userId, attributionTag);
     }
 
     /** @see AudioManager#getStreamVolume(int) */
@@ -4069,7 +4077,8 @@
 
     /** @see AudioManager#setMicrophoneMute(boolean) */
     @Override
-    public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
+    public void setMicrophoneMute(boolean on, String callingPackage, int userId,
+            String attributionTag) {
         // If we are being called by the system check for user we are going to change
         // so we handle user restrictions correctly.
         int uid = Binder.getCallingUid();
@@ -4084,8 +4093,8 @@
                         ? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE);
 
         // If OP_MUTE_MICROPHONE is set, disallow unmuting.
-        if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
+        if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid,
+                callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
             mmi.set(MediaMetrics.Property.EARLY_RETURN, "disallow unmuting").record();
             return;
         }
@@ -4921,7 +4930,7 @@
         }
 
         adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid,
-                hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
+                null, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
     }
 
     /** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */
@@ -4933,7 +4942,7 @@
             throw new SecurityException("Should only be called from system process");
         }
 
-        setStreamVolume(streamType, index, flags, packageName, packageName, uid,
+        setStreamVolume(streamType, index, flags, packageName, packageName, null, uid,
                 hasAudioSettingsPermission(uid, pid));
     }
 
@@ -6356,7 +6365,7 @@
 
     private void ensureValidAttributes(AudioVolumeGroup avg) {
         boolean hasAtLeastOneValidAudioAttributes = avg.getAudioAttributes().stream()
-                .anyMatch(aa -> !aa.equals(AudioProductStrategy.sDefaultAttributes));
+                .anyMatch(aa -> !aa.equals(AudioProductStrategy.getDefaultAttributes()));
         if (!hasAtLeastOneValidAudioAttributes) {
             throw new IllegalArgumentException("Volume Group " + avg.name()
                     + " has no valid audio attributes");
@@ -6404,7 +6413,7 @@
         private int mIndexMax;
         private int mLegacyStreamType = AudioSystem.STREAM_DEFAULT;
         private int mPublicStreamType = AudioSystem.STREAM_MUSIC;
-        private AudioAttributes mAudioAttributes = AudioProductStrategy.sDefaultAttributes;
+        private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes();
 
         // No API in AudioSystem to get a device from strategy or from attributes.
         // Need a valid public stream type to use current API getDeviceForStream
@@ -6417,8 +6426,9 @@
             if (DEBUG_VOL) {
                 Log.v(TAG, "VolumeGroupState for " + avg.toString());
             }
+            // mAudioAttributes is the default at this point
             for (final AudioAttributes aa : avg.getAudioAttributes()) {
-                if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
+                if (!aa.equals(mAudioAttributes)) {
                     mAudioAttributes = aa;
                     break;
                 }
@@ -8068,8 +8078,8 @@
     }
 
     public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
-            IAudioPolicyCallback pcb, int sdk) {
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName,
+            String attributionTag, int flags, IAudioPolicyCallback pcb, int sdk) {
         final int uid = Binder.getCallingUid();
         MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "focus")
                 .setUid(uid)
@@ -8121,7 +8131,7 @@
         }
         mmi.record();
         return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
-                clientId, callingPackageName, flags, sdk,
+                clientId, callingPackageName, attributionTag, flags, sdk,
                 forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/);
     }
 
@@ -8138,7 +8148,7 @@
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
         return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
-                clientId, callingPackageName, AudioManager.AUDIOFOCUS_FLAG_TEST,
+                clientId, callingPackageName, null, AudioManager.AUDIOFOCUS_FLAG_TEST,
                 sdk, false /*forceDuck*/, fakeUid);
     }
 
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index e6c4abfa..6fe1295 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -857,6 +857,7 @@
      * @param fd
      * @param clientId
      * @param callingPackageName
+     * @param attributionTag
      * @param flags
      * @param sdk
      * @param forceDuck only true if
@@ -868,7 +869,7 @@
      */
     protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
             IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
-            int flags, int sdk, boolean forceDuck, int testUid) {
+            String attributionTag, int flags, int sdk, boolean forceDuck, int testUid) {
         new MediaMetrics.Item(mMetricsId)
                 .setUid(Binder.getCallingUid())
                 .set(MediaMetrics.Property.CALLING_PACKAGE, callingPackageName)
@@ -903,7 +904,7 @@
         if ((flags != AudioManager.AUDIOFOCUS_FLAG_TEST)
                 // note we're using the real uid for appOp evaluation
                 && (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
-                        callingPackageName) != AppOpsManager.MODE_ALLOWED)) {
+                        callingPackageName, attributionTag, null) != AppOpsManager.MODE_ALLOWED)) {
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 54abc63..70ad4c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -263,7 +263,7 @@
             final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName);
 
             // Clear calling identity when checking LockPatternUtils for StrongAuth flags.
-            long identity = Binder.clearCallingIdentity();
+            final long identity1 = Binder.clearCallingIdentity();
             try {
                 if (isKeyguard && Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
                     // If this happens, something in KeyguardUpdateMonitor is wrong.
@@ -273,7 +273,7 @@
                     return;
                 }
             } finally {
-                Binder.restoreCallingIdentity(identity);
+                Binder.restoreCallingIdentity(identity1);
             }
 
             final boolean restricted = getContext().checkCallingPermission(MANAGE_FINGERPRINT)
@@ -297,11 +297,11 @@
                     provider.second.getSensorProperties(sensorId);
             if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
                     && sensorProps != null && sensorProps.isAnyUdfpsType()) {
-                identity = Binder.clearCallingIdentity();
+                final long identity2 = Binder.clearCallingIdentity();
                 try {
                     authenticateWithPrompt(operationId, sensorProps, userId, receiver);
                 } finally {
-                    Binder.restoreCallingIdentity(identity);
+                    Binder.restoreCallingIdentity(identity2);
                 }
             } else {
                 provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index b2d35f4..ed7d185 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -35,11 +35,14 @@
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceProxy;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
 import android.hardware.display.DisplayManager;
 import android.media.AudioManager;
 import android.nfc.INfcAdapter;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Process;
@@ -57,8 +60,8 @@
 import android.view.Surface;
 import android.view.WindowManagerGlobal;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.framework.protobuf.nano.MessageNano;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
@@ -447,6 +450,8 @@
         }
     };
 
+    private final FoldStateListener mFoldStateListener;
+
     public CameraServiceProxy(Context context) {
         super(context);
         mContext = context;
@@ -459,6 +464,14 @@
         // Don't keep any extra logging threads if not needed
         mLogWriterService.setKeepAliveTime(1, TimeUnit.SECONDS);
         mLogWriterService.allowCoreThreadTimeOut(true);
+
+        mFoldStateListener = new FoldStateListener(mContext, folded -> {
+            if (folded) {
+                setDeviceStateFlags(ICameraService.DEVICE_STATE_FOLDED);
+            } else {
+                clearDeviceStateFlags(ICameraService.DEVICE_STATE_FOLDED);
+            }
+        });
     }
 
     /**
@@ -471,7 +484,7 @@
      *
      * @see #clearDeviceStateFlags(int)
      */
-    public void setDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) {
+    private void setDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_NOTIFY_DEVICE_STATE);
             mDeviceState |= deviceStateFlags;
@@ -491,7 +504,7 @@
      *
      * @see #setDeviceStateFlags(int)
      */
-    public void clearDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) {
+    private void clearDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_NOTIFY_DEVICE_STATE);
             mDeviceState &= ~deviceStateFlags;
@@ -555,6 +568,9 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to register display window listener!");
             }
+
+            mContext.getSystemService(DeviceStateManager.class)
+                    .registerCallback(new HandlerExecutor(mHandler), mFoldStateListener);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 35f2957..9f806af 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -43,6 +43,7 @@
     // The display device does not manage these properties itself, they are set by
     // the display manager service.  The display device shouldn't really be looking at these.
     private int mCurrentLayerStack = -1;
+    private int mCurrentFlags = 0;
     private int mCurrentOrientation = -1;
     private Rect mCurrentLayerStackRect;
     private Rect mCurrentDisplayRect;
@@ -212,6 +213,19 @@
     }
 
     /**
+     * Sets the display flags while in a transaction.
+     *
+     * Valid display flags:
+     *  {@link SurfaceControl#DISPLAY_RECEIVES_INPUT}
+     */
+    public final void setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags) {
+        if (mCurrentFlags != flags) {
+            mCurrentFlags = flags;
+            t.setDisplayFlags(mDisplayToken, flags);
+        }
+    }
+
+    /**
      * Sets the display projection while in a transaction.
      *
      * @param orientation defines the display's orientation
@@ -298,6 +312,7 @@
         pw.println("mUniqueId=" + mUniqueId);
         pw.println("mDisplayToken=" + mDisplayToken);
         pw.println("mCurrentLayerStack=" + mCurrentLayerStack);
+        pw.println("mCurrentFlags=" + mCurrentFlags);
         pw.println("mCurrentOrientation=" + mCurrentOrientation);
         pw.println("mCurrentLayerStackRect=" + mCurrentLayerStackRect);
         pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 83fc966..f9f98e0 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -2042,7 +2042,9 @@
         public void observe() {
             StatusBarManagerInternal statusBar =
                     LocalServices.getService(StatusBarManagerInternal.class);
-            statusBar.setUdfpsHbmListener(this);
+            if (statusBar != null) {
+                statusBar.setUdfpsHbmListener(this);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 9acb4c8..5186744 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -512,6 +514,11 @@
             boolean isBlanked) {
         // Set the layer stack.
         device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
+        // Also inform whether the device is the same one sent to inputflinger for its layerstack.
+        // TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
+        device.setDisplayFlagsLocked(t,
+                device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE
+                        ? SurfaceControl.DISPLAY_RECEIVES_INPUT : 0);
 
         // Set the color mode and allowed display mode.
         if (device == mPrimaryDisplayDevice) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 7fa0b21..851accc 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -162,7 +162,8 @@
     private final ReduceBrightColorsTintController mReduceBrightColorsTintController =
             new ReduceBrightColorsTintController();
 
-    private final Handler mHandler;
+    @VisibleForTesting
+    final Handler mHandler;
 
     private final AppSaturationController mAppSaturationController = new AppSaturationController();
 
@@ -404,13 +405,13 @@
         // existing activated state. This ensures consistency of tint across the color mode change.
         onDisplayColorModeChanged(getColorModeInternal());
 
+        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         if (mNightDisplayTintController.isAvailable(getContext())) {
             // Reset the activated state.
             mNightDisplayTintController.setActivated(null);
 
             // Prepare the night display color transformation matrix.
-            mNightDisplayTintController
-                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+            mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix());
             mNightDisplayTintController
                     .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
 
@@ -432,8 +433,7 @@
         }
 
         if (mReduceBrightColorsTintController.isAvailable(getContext())) {
-            mReduceBrightColorsTintController
-                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+            mReduceBrightColorsTintController.setUp(getContext(), dtm.needsLinearColorMatrix());
             onReduceBrightColorsStrengthLevelChanged();
             final boolean reset = resetReduceBrightColors();
             if (!reset) {
@@ -540,8 +540,8 @@
         mDisplayWhiteBalanceTintController.cancelAnimator();
 
         if (mNightDisplayTintController.isAvailable(getContext())) {
-            mNightDisplayTintController
-                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
+            final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+            mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix(mode));
             mNightDisplayTintController
                     .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
         }
@@ -735,10 +735,11 @@
     @VisibleForTesting
     void updateDisplayWhiteBalanceStatus() {
         boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
+        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled()
                 && !mNightDisplayTintController.isActivated()
                 && !isAccessibilityEnabled()
-                && DisplayTransformManager.needsLinearColorMatrix());
+                && dtm.needsLinearColorMatrix());
         boolean activated = mDisplayWhiteBalanceTintController.isActivated();
 
         if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 5c68c51..0dba9e1 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -239,7 +239,7 @@
     /**
      * Return true when the color matrix works in linear space.
      */
-    public static boolean needsLinearColorMatrix() {
+    public boolean needsLinearColorMatrix() {
         return SystemProperties.getInt(PERSISTENT_PROPERTY_DISPLAY_COLOR,
                 DISPLAY_COLOR_UNMANAGED) != DISPLAY_COLOR_UNMANAGED;
     }
@@ -247,7 +247,7 @@
     /**
      * Return true when the specified colorMode requires the color matrix to work in linear space.
      */
-    public static boolean needsLinearColorMatrix(int colorMode) {
+    public boolean needsLinearColorMatrix(int colorMode) {
         return colorMode != ColorDisplayManager.COLOR_MODE_SATURATED;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 8405bbe..d422d51 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -88,7 +88,7 @@
                 tv.updateActiveSource(current, "ActiveSourceHandler");
                 invokeCallback(HdmiControlManager.RESULT_SUCCESS);
             } else {
-                tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true,
+                tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress,
                         mCallback);
             }
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index fefe953..5de89c9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -317,12 +317,25 @@
                 R.bool.config_cecHdmiCecVersion20_allowed,
                 R.bool.config_cecHdmiCecVersion20_default);
 
+        Setting routingControlControl = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
+                R.bool.config_cecRoutingControl_userConfigurable);
+        routingControlControl.registerValue(HdmiControlManager.ROUTING_CONTROL_ENABLED,
+                R.bool.config_cecRoutingControlEnabled_allowed,
+                R.bool.config_cecRoutingControlEnabled_default);
+        routingControlControl.registerValue(HdmiControlManager.ROUTING_CONTROL_DISABLED,
+                R.bool.config_cecRoutingControlDisabled_allowed,
+                R.bool.config_cecRoutingControlDisabled_default);
+
         Setting powerControlMode = registerSetting(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 R.bool.config_cecPowerControlMode_userConfigurable);
         powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV,
                 R.bool.config_cecPowerControlModeTv_allowed,
                 R.bool.config_cecPowerControlModeTv_default);
+        powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM,
+                R.bool.config_cecPowerControlModeTvAndAudioSystem_allowed,
+                R.bool.config_cecPowerControlModeTvAndAudioSystem_default);
         powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST,
                 R.bool.config_cecPowerControlModeBroadcast_allowed,
                 R.bool.config_cecPowerControlModeBroadcast_default);
@@ -342,6 +355,16 @@
                 R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed,
                 R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
 
+        Setting systemAudioControl = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
+                R.bool.config_cecSystemAudioControl_userConfigurable);
+        systemAudioControl.registerValue(HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED,
+                R.bool.config_cecSystemAudioControlEnabled_allowed,
+                R.bool.config_cecSystemAudioControlEnabled_default);
+        systemAudioControl.registerValue(HdmiControlManager.SYSTEM_AUDIO_CONTROL_DISABLED,
+                R.bool.config_cecSystemAudioControlDisabled_allowed,
+                R.bool.config_cecSystemAudioControlDisabled_default);
+
         Setting systemAudioModeMuting = registerSetting(
                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                 R.bool.config_cecSystemAudioModeMuting_userConfigurable);
@@ -498,12 +521,16 @@
                 return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
                 return STORAGE_SHARED_PREFS;
+            case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL:
+                return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
                 return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
                 return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
                 return STORAGE_SHARED_PREFS;
+            case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL:
+                return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING:
                 return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY:
@@ -535,12 +562,16 @@
                 return Global.HDMI_CONTROL_ENABLED;
             case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
                 return setting.getName();
+            case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL:
+                return Global.HDMI_CEC_SWITCH_ENABLED;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
                 return Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP;
             case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
                 return Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
                 return setting.getName();
+            case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL:
+                return Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED;
             case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING:
                 return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY:
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 23b5c14..698ee0b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -481,4 +481,113 @@
         // return muting ? CEC_KEYCODE_MUTE_FUNCTION : CEC_KEYCODE_RESTORE_VOLUME_FUNCTION;
         return CEC_KEYCODE_MUTE;
     }
+
+    public static String getKeycodeType(byte keycode) {
+        switch (keycode) {
+            case CEC_KEYCODE_UP:
+            case CEC_KEYCODE_DOWN:
+            case CEC_KEYCODE_LEFT:
+            case CEC_KEYCODE_RIGHT:
+            case CEC_KEYCODE_RIGHT_UP:
+            case CEC_KEYCODE_RIGHT_DOWN:
+            case CEC_KEYCODE_LEFT_UP:
+            case CEC_KEYCODE_LEFT_DOWN:
+            case CEC_KEYCODE_PAGE_UP:
+            case CEC_KEYCODE_PAGE_DOWN:
+            case CEC_KEYCODE_EXIT:
+                return "Navigation";
+            case CEC_KEYCODE_ROOT_MENU:
+            case CEC_KEYCODE_SETUP_MENU:
+            case CEC_KEYCODE_CONTENTS_MENU:
+            case CEC_KEYCODE_FAVORITE_MENU:
+            case CEC_KEYCODE_MEDIA_TOP_MENU:
+            case CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU:
+                return "Menu";
+            case CEC_KEYCODE_VOLUME_UP:
+                return "Volume up";
+            case CEC_KEYCODE_VOLUME_DOWN:
+                return "Volume down";
+            case CEC_KEYCODE_MUTE:
+                return "Volume mute";
+            case CEC_KEYCODE_POWER:
+                return "Power";
+            case CEC_KEYCODE_POWER_TOGGLE_FUNCTION:
+                return "Power toggle";
+            case CEC_KEYCODE_POWER_OFF_FUNCTION:
+                return "Power off";
+            case CEC_KEYCODE_POWER_ON_FUNCTION:
+                return "Power on";
+            case CEC_KEYCODE_F1_BLUE:
+            case CEC_KEYCODE_F2_RED:
+            case CEC_KEYCODE_F3_GREEN:
+            case CEC_KEYCODE_F4_YELLOW:
+            case CEC_KEYCODE_F5:
+                return "Function key";
+            case CEC_KEYCODE_NEXT_FAVORITE:
+            case CEC_KEYCODE_CHANNEL_UP:
+            case CEC_KEYCODE_CHANNEL_DOWN:
+            case CEC_KEYCODE_PREVIOUS_CHANNEL:
+                return "Channel";
+            case CEC_KEYCODE_NUMBER_11:
+            case CEC_KEYCODE_NUMBER_12:
+            case CEC_KEYCODE_NUMBER_0_OR_NUMBER_10:
+            case CEC_KEYCODE_NUMBERS_1:
+            case CEC_KEYCODE_NUMBERS_2:
+            case CEC_KEYCODE_NUMBERS_3:
+            case CEC_KEYCODE_NUMBERS_4:
+            case CEC_KEYCODE_NUMBERS_5:
+            case CEC_KEYCODE_NUMBERS_6:
+            case CEC_KEYCODE_NUMBERS_7:
+            case CEC_KEYCODE_NUMBERS_8:
+            case CEC_KEYCODE_NUMBERS_9:
+                return "Number";
+            case CEC_KEYCODE_PLAY:
+            case CEC_KEYCODE_STOP:
+            case CEC_KEYCODE_PAUSE:
+            case CEC_KEYCODE_RECORD:
+            case CEC_KEYCODE_REWIND:
+            case CEC_KEYCODE_FAST_FORWARD:
+            case CEC_KEYCODE_EJECT:
+            case CEC_KEYCODE_FORWARD:
+            case CEC_KEYCODE_BACKWARD:
+            case CEC_KEYCODE_STOP_RECORD:
+            case CEC_KEYCODE_PAUSE_RECORD:
+            case CEC_KEYCODE_ANGLE:
+            case CEC_KEYCODE_SUB_PICTURE:
+            case CEC_KEYCODE_VIDEO_ON_DEMAND:
+                return "Media";
+            case CEC_KEYCODE_PLAY_FUNCTION:
+            case CEC_KEYCODE_PAUSE_PLAY_FUNCTION:
+            case CEC_KEYCODE_RECORD_FUNCTION:
+            case CEC_KEYCODE_PAUSE_RECORD_FUNCTION:
+            case CEC_KEYCODE_STOP_FUNCTION:
+            case CEC_KEYCODE_MUTE_FUNCTION:
+            case CEC_KEYCODE_RESTORE_VOLUME_FUNCTION:
+            case CEC_KEYCODE_TUNE_FUNCTION:
+            case CEC_KEYCODE_SELECT_MEDIA_FUNCTION:
+            case CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION:
+            case CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION:
+                return "Functional";
+            case CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE:
+            case CEC_KEYCODE_TIMER_PROGRAMMING:
+                return "Timer";
+            case CEC_KEYCODE_SOUND_SELECT:
+            case CEC_KEYCODE_SELECT_SOUND_PRESENTATION:
+            case CEC_KEYCODE_SELECT_BROADCAST_TYPE:
+            case CEC_KEYCODE_INPUT_SELECT:
+            case CEC_KEYCODE_SELECT:
+                return "Select";
+            case CEC_KEYCODE_NUMBER_ENTRY_MODE:
+            case CEC_KEYCODE_DOT:
+            case CEC_KEYCODE_CLEAR:
+            case CEC_KEYCODE_ENTER:
+            case CEC_KEYCODE_DISPLAY_INFORMATION:
+            case CEC_KEYCODE_HELP:
+            case CEC_KEYCODE_DATA:
+            case CEC_KEYCODE_INITIAL_CONFIGURATION:
+                return "General";
+            default:
+                return "Unknown";
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index a2cb78d..63366f3 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -22,6 +22,7 @@
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.input.InputManager;
+import android.hardware.tv.cec.V1_0.Result;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
 import android.os.Handler;
@@ -285,7 +286,7 @@
             case Constants.MESSAGE_GIVE_OSD_NAME:
                 return handleGiveOsdName(message);
             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
-                return handleGiveDeviceVendorId(null);
+                return handleGiveDeviceVendorId(message);
             case Constants.MESSAGE_CEC_VERSION:
                 return handleCecVersion();
             case Constants.MESSAGE_GET_CEC_VERSION:
@@ -393,12 +394,16 @@
 
     @ServiceThreadOnly
     @Constants.HandleMessageResult
-    protected int handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) {
+    protected int handleGiveDeviceVendorId(HdmiCecMessage message) {
         assertRunOnServiceThread();
         int vendorId = mService.getVendorId();
-        HdmiCecMessage cecMessage =
-                HdmiCecMessageBuilder.buildDeviceVendorIdCommand(mAddress, vendorId);
-        mService.sendCecCommand(cecMessage, callback);
+        if (vendorId == Result.FAILURE_UNKNOWN) {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
+        } else {
+            HdmiCecMessage cecMessage =
+                    HdmiCecMessageBuilder.buildDeviceVendorIdCommand(mAddress, vendorId);
+            mService.sendCecCommand(cecMessage);
+        }
         return Constants.HANDLED;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 0bb1285..93b0560 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -34,7 +34,6 @@
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager.TvInputCallback;
 import android.os.SystemProperties;
-import android.provider.Settings.Global;
 import android.sysprop.HdmiProperties;
 import android.util.Slog;
 
@@ -108,10 +107,12 @@
 
     protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
-        mRoutingControlFeatureEnabled =
-            mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
-        mSystemAudioControlFeatureEnabled =
-            mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
+        mRoutingControlFeatureEnabled = mService.getHdmiCecConfig().getIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL)
+                    == HdmiControlManager.ROUTING_CONTROL_ENABLED;
+        mSystemAudioControlFeatureEnabled = mService.getHdmiCecConfig().getIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL)
+                    == HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED;
     }
 
     private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
@@ -857,7 +858,7 @@
         HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
     }
 
-    void onSystemAduioControlFeatureSupportChanged(boolean enabled) {
+    void onSystemAudioControlFeatureSupportChanged(boolean enabled) {
         setSystemAudioControlFeatureEnabled(enabled);
         if (enabled) {
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
@@ -873,7 +874,7 @@
     }
 
     @ServiceThreadOnly
-    void setRoutingControlFeatureEnables(boolean enabled) {
+    void setRoutingControlFeatureEnabled(boolean enabled) {
         assertRunOnServiceThread();
         synchronized (mLock) {
             mRoutingControlFeatureEnabled = enabled;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 37ee76b..1276aa3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -140,13 +140,10 @@
         // Invalidate the internal active source record when going to standby
         mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
                 "HdmiCecLocalDevicePlayback#onStandby()");
-        boolean mTvSendStandbyOnSleep = mService.getHdmiCecConfig().getIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
-                    == HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED;
         if (!wasActiveSource) {
             return;
         }
-        if (initiatedByCec || !mTvSendStandbyOnSleep) {
+        if (initiatedByCec) {
             mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(mAddress,
                             mService.getPhysicalAddress()));
             return;
@@ -155,13 +152,20 @@
             case HdmiControlService.STANDBY_SCREEN_OFF:
                 // Get latest setting value
                 @HdmiControlManager.PowerControlMode
-                String sendStandbyOnSleep = mService.getHdmiCecConfig().getStringValue(
+                String powerControlMode = mService.getHdmiCecConfig().getStringValue(
                         HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
-                switch (sendStandbyOnSleep) {
+                switch (powerControlMode) {
                     case HdmiControlManager.POWER_CONTROL_MODE_TV:
                         mService.sendCecCommand(
                                 HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
                         break;
+                    case HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM:
+                        mService.sendCecCommand(
+                                HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+                        mService.sendCecCommand(
+                                HdmiCecMessageBuilder.buildStandby(mAddress,
+                                        Constants.ADDR_AUDIO_SYSTEM));
+                        break;
                     case HdmiControlManager.POWER_CONTROL_MODE_BROADCAST:
                         mService.sendCecCommand(
                                 HdmiCecMessageBuilder.buildStandby(mAddress,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 1c726e0..0c7b3f6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -107,14 +107,18 @@
     @ServiceThreadOnly
     protected void sendStandby(int deviceId) {
         assertRunOnServiceThread();
-        String sendStandbyOnSleep = mService.getHdmiCecConfig().getStringValue(
+        String powerControlMode = mService.getHdmiCecConfig().getStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
-        if (sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST)) {
+        if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST)) {
             mService.sendCecCommand(
                     HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
             return;
         }
         mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+        if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM)) {
+            mService.sendCecCommand(
+                    HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_AUDIO_SYSTEM));
+        }
     }
 
     @ServiceThreadOnly
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index acfeb6c..a887463 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -42,7 +42,6 @@
 import android.media.AudioSystem;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager.TvInputCallback;
-import android.provider.Settings.Global;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 
@@ -155,8 +154,9 @@
     HdmiCecLocalDeviceTv(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_TV);
         mPrevPortId = Constants.INVALID_PORT_ID;
-        mSystemAudioControlFeatureEnabled =
-                mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
+        mSystemAudioControlFeatureEnabled = service.getHdmiCecConfig().getIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL)
+                    == HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED;
         mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
     }
 
@@ -374,12 +374,11 @@
             return;
         }
         int newPath = mService.portIdToPath(portId);
-        startRoutingControl(oldPath, newPath, true, callback);
+        startRoutingControl(oldPath, newPath, callback);
     }
 
     @ServiceThreadOnly
-    void startRoutingControl(int oldPath, int newPath, boolean queryDevicePowerStatus,
-            IHdmiControlCallback callback) {
+    void startRoutingControl(int oldPath, int newPath, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
         if (oldPath == newPath) {
             return;
@@ -389,7 +388,7 @@
         mService.sendCecCommand(routingChange);
         removeAction(RoutingControlAction.class);
         addAndStartAction(
-                new RoutingControlAction(this, newPath, queryDevicePowerStatus, callback));
+                new RoutingControlAction(this, newPath, callback));
     }
 
     @ServiceThreadOnly
@@ -567,7 +566,7 @@
         if (isTailOfActivePath(path, getActivePath())) {
             int newPath = mService.portIdToPath(getActivePortId());
             setActivePath(newPath);
-            startRoutingControl(getActivePath(), newPath, false, null);
+            startRoutingControl(getActivePath(), newPath, null);
             return true;
         }
         return false;
@@ -612,7 +611,7 @@
             getActiveSource().invalidate();
             removeAction(RoutingControlAction.class);
             int newPath = HdmiUtils.twoBytesToInt(params, 2);
-            addAndStartAction(new RoutingControlAction(this, newPath, true, null));
+            addAndStartAction(new RoutingControlAction(this, newPath, null));
         }
         return Constants.HANDLED;
     }
@@ -1189,7 +1188,7 @@
         // Seq #23
         if (isTailOfActivePath(path, getActivePath())) {
             int newPath = mService.portIdToPath(getActivePortId());
-            startRoutingControl(getActivePath(), newPath, true, null);
+            startRoutingControl(getActivePath(), newPath, null);
         }
     }
 
@@ -1207,7 +1206,7 @@
             if (!routingForBootup && !isProhibitMode()) {
                 int newPath = mService.portIdToPath(getActivePortId());
                 setActivePath(newPath);
-                startRoutingControl(getActivePath(), newPath, routingForBootup, null);
+                startRoutingControl(getActivePath(), newPath, null);
             }
         } else {
             int activePath = mService.getPhysicalAddress();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index c85fd50..15a3167 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -119,6 +119,10 @@
         if (mParams.length > 0) {
             if (filterMessageParameters(mOpcode)) {
                 s.append(String.format(" <Redacted len=%d>", mParams.length));
+            } else if (isUserControlPressedMessage(mOpcode)) {
+                s.append(
+                        String.format(
+                                " <Keycode type = %s>", HdmiCecKeycode.getKeycodeType(mParams[0])));
             } else {
                 for (byte data : mParams) {
                     s.append(String.format(":%02X", data));
@@ -287,7 +291,6 @@
 
     private static boolean filterMessageParameters(int opcode) {
         switch (opcode) {
-            case Constants.MESSAGE_USER_CONTROL_PRESSED:
             case Constants.MESSAGE_USER_CONTROL_RELEASED:
             case Constants.MESSAGE_SET_OSD_NAME:
             case Constants.MESSAGE_SET_OSD_STRING:
@@ -300,5 +303,9 @@
                 return false;
         }
     }
+
+    private static boolean isUserControlPressedMessage(int opcode) {
+        return Constants.MESSAGE_USER_CONTROL_PRESSED == opcode;
+    }
 }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index a086bda..c7d0e9e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -618,6 +618,53 @@
                         initializeCec(INITIATED_BY_ENABLE_CEC);
                     }
                 }, mServiceThreadExecutor);
+        mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
+                new HdmiCecConfig.SettingChangeListener() {
+                    @Override
+                    public void onChange(String setting) {
+                        boolean enabled = mHdmiCecConfig.getIntValue(
+                                HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL)
+                                    == HdmiControlManager.ROUTING_CONTROL_ENABLED;
+                        if (isAudioSystemDevice()) {
+                            if (audioSystem() == null) {
+                                Slog.w(TAG, "Switch device has not registered yet."
+                                        + " Can't turn routing on.");
+                            } else {
+                                audioSystem().setRoutingControlFeatureEnabled(enabled);
+                            }
+                        }
+                    }
+                }, mServiceThreadExecutor);
+        mHdmiCecConfig.registerChangeListener(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
+                new HdmiCecConfig.SettingChangeListener() {
+                    @Override
+                    public void onChange(String setting) {
+                        boolean enabled = mHdmiCecConfig.getIntValue(
+                                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL)
+                                    == HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED;
+                        if (isTvDeviceEnabled()) {
+                            tv().setSystemAudioControlFeatureEnabled(enabled);
+                        }
+                        if (isAudioSystemDevice()) {
+                            if (audioSystem() == null) {
+                                Slog.e(TAG, "Audio System device has not registered yet."
+                                        + " Can't turn system audio mode on.");
+                            } else {
+                                audioSystem().onSystemAudioControlFeatureSupportChanged(enabled);
+                            }
+                        }
+                    }
+                }, mServiceThreadExecutor);
+        mHdmiCecConfig.registerChangeListener(
+                HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+                new HdmiCecConfig.SettingChangeListener() {
+                    @Override
+                    public void onChange(String setting) {
+                        setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue(
+                                HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE));
+                    }
+                }, mServiceThreadExecutor);
         mHdmiCecConfig.registerChangeListener(
                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
                 new HdmiCecConfig.SettingChangeListener() {
@@ -757,11 +804,8 @@
     private void registerContentObserver() {
         ContentResolver resolver = getContext().getContentResolver();
         String[] settings = new String[] {
-                Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
-                Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
                 Global.MHL_INPUT_SWITCHING_ENABLED,
                 Global.MHL_POWER_CHARGE_ENABLED,
-                Global.HDMI_CEC_SWITCH_ENABLED,
                 Global.DEVICE_NAME
         };
         for (String s : settings) {
@@ -781,33 +825,6 @@
             String option = uri.getLastPathSegment();
             boolean enabled = readBooleanSetting(option, true);
             switch (option) {
-                case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED:
-                    setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue(
-                            HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE));
-                    break;
-                case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED:
-                    if (isTvDeviceEnabled()) {
-                        tv().setSystemAudioControlFeatureEnabled(enabled);
-                    }
-                    if (isAudioSystemDevice()) {
-                        if (audioSystem() == null) {
-                            Slog.e(TAG, "Audio System device has not registered yet."
-                                    + " Can't turn system audio mode on.");
-                            break;
-                        }
-                        audioSystem().onSystemAduioControlFeatureSupportChanged(enabled);
-                    }
-                    break;
-                case Global.HDMI_CEC_SWITCH_ENABLED:
-                    if (isAudioSystemDevice()) {
-                        if (audioSystem() == null) {
-                            Slog.w(TAG, "Switch device has not registered yet."
-                                    + " Can't turn routing on.");
-                            break;
-                        }
-                        audioSystem().setRoutingControlFeatureEnables(enabled);
-                    }
-                    break;
                 case Global.MHL_INPUT_SWITCHING_ENABLED:
                     setMhlInputChangeEnabled(enabled);
                     break;
@@ -2359,7 +2376,7 @@
         @Override
         public List<String> getUserCecSettings() {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 return HdmiControlService.this.getHdmiCecConfig().getUserSettings();
             } finally {
@@ -2370,7 +2387,7 @@
         @Override
         public List<String> getAllowedCecSettingStringValues(String name) {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 return HdmiControlService.this.getHdmiCecConfig().getAllowedStringValues(name);
             } finally {
@@ -2381,7 +2398,7 @@
         @Override
         public int[] getAllowedCecSettingIntValues(String name) {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 List<Integer> allowedValues =
                         HdmiControlService.this.getHdmiCecConfig().getAllowedIntValues(name);
@@ -2394,7 +2411,7 @@
         @Override
         public String getCecSettingStringValue(String name) {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 return HdmiControlService.this.getHdmiCecConfig().getStringValue(name);
             } finally {
@@ -2405,7 +2422,7 @@
         @Override
         public void setCecSettingStringValue(String name, String value) {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 HdmiControlService.this.getHdmiCecConfig().setStringValue(name, value);
             } finally {
@@ -2416,7 +2433,7 @@
         @Override
         public int getCecSettingIntValue(String name) {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 return HdmiControlService.this.getHdmiCecConfig().getIntValue(name);
             } finally {
@@ -2427,7 +2444,7 @@
         @Override
         public void setCecSettingIntValue(String name, int value) {
             initBinderCall();
-            long token = Binder.clearCallingIdentity();
+            final long token = Binder.clearCallingIdentity();
             try {
                 HdmiControlService.this.getHdmiCecConfig().setIntValue(name, value);
             } finally {
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 979e7a4..3dcf72e 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -178,10 +178,11 @@
         if (service.isAudioSystemDevice()) {
             return false;
         }
-        @HdmiControlManager.PowerControlMode String sendStandbyOnSleep =
+        @HdmiControlManager.PowerControlMode String powerControlMode =
                 service.getHdmiCecConfig().getStringValue(
                         HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
-        return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
+        return powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM)
+                || powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 
     private static int getTargetCecVersion(HdmiCecLocalDevice localDevice,
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index b9404e4..0c4fb26 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -17,11 +17,10 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.util.Slog;
 
-import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * Feature action for routing control. Exchanges routing-related commands with other devices
@@ -41,23 +40,12 @@
 
     // State in which we wait for <Routing Information> to arrive. If timed out, we use the
     // latest routing path to set the new active source.
-    private static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
-
-    // State in which we wait for <Report Power Status> in response to <Give Device Power Status>
-    // we have sent. If the response tells us the device power is on, we send <Set Stream Path>
-    // to make it the active source. Otherwise we do not send <Set Stream Path>, and possibly
-    // just show the blank screen.
-    private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2;
+    @VisibleForTesting
+    static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
 
     // Time out in millseconds used for <Routing Information>
     private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
 
-    // Time out in milliseconds used for <Report Power Status>
-    private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000;
-
-    // true if <Give Power Status> should be sent once the new active routing path is determined.
-    private final boolean mQueryDevicePowerStatus;
-
     // If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when
     // the routing control/active source change happens. The listener should be called if
     // the events are triggered by external events such as manual switch port change or incoming
@@ -67,11 +55,9 @@
     // The latest routing path. Updated by each <Routing Information> from CEC switches.
     private int mCurrentRoutingPath;
 
-    RoutingControlAction(HdmiCecLocalDevice localDevice, int path, boolean queryDevicePowerStatus,
-            IHdmiControlCallback callback) {
+    RoutingControlAction(HdmiCecLocalDevice localDevice, int path, IHdmiControlCallback callback) {
         super(localDevice, callback);
         mCurrentRoutingPath = path;
-        mQueryDevicePowerStatus = queryDevicePowerStatus;
         // Callback is non-null when routing control action is brought up by binder API. Use
         // this as an indicator for the input change notification. These API calls will get
         // the result through this callback, not through notification. Any other events that
@@ -104,39 +90,16 @@
             removeActionExcept(RoutingControlAction.class, this);
             addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
             return true;
-        } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
-                  && opcode == Constants.MESSAGE_REPORT_POWER_STATUS) {
-            handleReportPowerStatus(cmd.getParams()[0]);
-            return true;
         }
         return false;
     }
 
-    private void handleReportPowerStatus(int devicePowerStatus) {
-        if (isPowerOnOrTransient(getTvPowerStatus())) {
-            updateActiveInput();
-            if (isPowerOnOrTransient(devicePowerStatus)) {
-                sendSetStreamPath();
-            }
-        }
-        finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
-    }
-
     private void updateActiveInput() {
         HdmiCecLocalDeviceTv tv = tv();
         tv.setPrevPortId(tv.getActivePortId());
         tv.updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
     }
 
-    private int getTvPowerStatus() {
-        return tv().getPowerStatus();
-    }
-
-    private static boolean isPowerOnOrTransient(int status) {
-        return status == HdmiControlManager.POWER_STATUS_ON
-                || status == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
-    }
-
     private void sendSetStreamPath() {
         sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(),
                 mCurrentRoutingPath));
@@ -150,46 +113,13 @@
         }
         switch (timeoutState) {
             case STATE_WAIT_FOR_ROUTING_INFORMATION:
-                HdmiDeviceInfo device =
-                        localDevice().mService.getHdmiCecNetwork().getDeviceInfoByPath(
-                                mCurrentRoutingPath);
-                if (device != null && mQueryDevicePowerStatus) {
-                    int deviceLogicalAddress = device.getLogicalAddress();
-                    queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() {
-                        @Override
-                        public void onSendCompleted(int error) {
-                            handlDevicePowerStatusAckResult(
-                                    error == HdmiControlManager.RESULT_SUCCESS);
-                        }
-                    });
-                } else {
-                    updateActiveInput();
-                    finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
-                }
-                return;
-            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
-                if (isPowerOnOrTransient(getTvPowerStatus())) {
-                    updateActiveInput();
-                    sendSetStreamPath();
-                }
+                updateActiveInput();
+                sendSetStreamPath();
                 finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
                 return;
-        }
-    }
-
-    private void queryDevicePowerStatus(int address, SendMessageCallback callback) {
-        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address),
-                callback);
-    }
-
-    private void handlDevicePowerStatusAckResult(boolean acked) {
-        if (acked) {
-            mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
-            addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
-        } else {
-            updateActiveInput();
-            sendSetStreamPath();
-            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
+            default:
+                Slog.e("CEC", "Invalid timeoutState (" + timeoutState + ").");
+                return;
         }
     }
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 9fcc9a1..d3083ca 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2856,8 +2856,7 @@
         };
         for (File baseDir: baseDirs) {
             File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
-            try {
-                InputStream stream = new FileInputStream(confFile);
+            try (InputStream stream = new FileInputStream(confFile)) {
                 names.addAll(ConfigurationProcessor.processExcludedDeviceNames(stream));
             } catch (FileNotFoundException e) {
                 // It's ok if the file does not exist.
@@ -2890,8 +2889,7 @@
         final File baseDir = Environment.getVendorDirectory();
         final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);
 
-        try {
-            final InputStream stream = new FileInputStream(confFile);
+        try (final InputStream stream = new FileInputStream(confFile)) {
             return ConfigurationProcessor.processInputPortAssociations(stream);
         } catch (FileNotFoundException e) {
             // Most of the time, file will not exist, which is expected.
@@ -3012,10 +3010,10 @@
             @Override
             public void visitKeyboardLayout(Resources resources,
                     int keyboardLayoutResId, KeyboardLayout layout) {
-                try {
+                try (final InputStreamReader stream = new InputStreamReader(
+                               resources.openRawResource(keyboardLayoutResId))) {
                     result[0] = layout.getDescriptor();
-                    result[1] = Streams.readFully(new InputStreamReader(
-                            resources.openRawResource(keyboardLayoutResId)));
+                    result[1] = Streams.readFully(stream);
                 } catch (IOException ex) {
                 } catch (NotFoundException ex) {
                 }
diff --git a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
index 1967e02..e375007 100644
--- a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
@@ -82,7 +82,7 @@
     }
 
     public void addListener(CallerIdentity callerIdentity, IGnssAntennaInfoListener listener) {
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             putRegistration(listener.asBinder(),
                     new AntennaInfoListenerRegistration(callerIdentity, listener));
@@ -92,7 +92,7 @@
     }
 
     public void removeListener(IGnssAntennaInfoListener listener) {
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             removeRegistration(listener.asBinder());
         } finally {
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index f3dcfbb..8787649 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -68,8 +68,6 @@
 import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -138,13 +136,6 @@
     private static final int AGPS_SUPL_MODE_MSA = 0x02;
     private static final int AGPS_SUPL_MODE_MSB = 0x01;
 
-    // handler messages
-    private static final int INJECT_NTP_TIME = 5;
-    private static final int DOWNLOAD_PSDS_DATA = 6;
-    private static final int REQUEST_LOCATION = 16;
-    private static final int REPORT_LOCATION = 17; // HAL reports location
-    private static final int REPORT_SV_STATUS = 18; // HAL reports SV status
-
     // TCP/IP constants.
     // Valid TCP/UDP port range is (0, 65535].
     private static final int TCP_MIN_PORT = 0;
@@ -402,7 +393,7 @@
                 BatteryStats.SERVICE_NAME));
 
         // Construct internal handler
-        mHandler = new ProviderHandler(FgThread.getHandler().getLooper());
+        mHandler = FgThread.getHandler();
 
         // Load GPS configuration and register listeners in the background:
         // some operations, such as opening files and registering broadcast receivers, can take a
@@ -530,7 +521,7 @@
         if (mSupportsPsds) {
             synchronized (mLock) {
                 for (int psdsType : mPendingDownloadPsdsTypes) {
-                    sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null);
+                    postWithWakeLockHeld(() -> handleDownloadPsdsData(psdsType));
                 }
                 mPendingDownloadPsdsTypes.clear();
             }
@@ -654,9 +645,7 @@
                 synchronized (mLock) {
                     backoffMillis = mPsdsBackOff.nextBackoffMillis();
                 }
-                mHandler.sendMessageDelayed(
-                        mHandler.obtainMessage(DOWNLOAD_PSDS_DATA, psdsType, 0, null),
-                        backoffMillis);
+                mHandler.postDelayed(() -> handleDownloadPsdsData(psdsType), backoffMillis);
             }
 
             // Release wake lock held by task, synchronize on mLock in case multiple
@@ -976,8 +965,8 @@
             requestUtcTime();
         } else if ("force_psds_injection".equals(command)) {
             if (mSupportsPsds) {
-                sendMessage(DOWNLOAD_PSDS_DATA, GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX,
-                        null);
+                postWithWakeLockHeld(() -> handleDownloadPsdsData(
+                        GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX));
             }
         } else if ("request_power_stats".equals(command)) {
             mGnssNative.requestPowerStats();
@@ -1314,7 +1303,7 @@
 
     private void requestUtcTime() {
         if (DEBUG) Log.d(TAG, "utcTimeRequest");
-        sendMessage(INJECT_NTP_TIME, 0, null);
+        postWithWakeLockHeld(mNtpTimeHelper::retrieveAndInjectNtpTime);
     }
 
     private void requestRefLocation() {
@@ -1348,75 +1337,17 @@
         }
     }
 
-    boolean isInEmergencySession() {
-        return mNIHandler.getInEmergency();
-    }
-
-    private void sendMessage(int message, int arg, Object obj) {
+    private void postWithWakeLockHeld(Runnable runnable) {
         // hold a wake lock until this message is delivered
         // note that this assumes the message will not be removed from the queue before
         // it is handled (otherwise the wake lock would be leaked).
         mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
-        if (DEBUG) {
-            Log.d(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
-                    + ", " + obj + ")");
-        }
-        mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
-    }
-
-    private final class ProviderHandler extends Handler {
-        ProviderHandler(Looper looper) {
-            super(looper, null, true /*async*/);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            int message = msg.what;
-            switch (message) {
-                case INJECT_NTP_TIME:
-                    mNtpTimeHelper.retrieveAndInjectNtpTime();
-                    break;
-                case REQUEST_LOCATION:
-                    handleRequestLocation(msg.arg1 == 1, (boolean) msg.obj);
-                    break;
-                case DOWNLOAD_PSDS_DATA:
-                    handleDownloadPsdsData(msg.arg1);
-                    break;
-                case REPORT_LOCATION:
-                    handleReportLocation(msg.arg1 == 1, (Location) msg.obj);
-                    break;
-                case REPORT_SV_STATUS:
-                    handleReportSvStatus((GnssStatus) msg.obj);
-                    break;
-            }
-            if (msg.arg2 == 1) {
-                // wakelock was taken for this message, release it
-                mWakeLock.release();
-                if (DEBUG) {
-                    Log.d(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
-                            + ", " + msg.arg1 + ", " + msg.obj + ")");
-                }
-            }
-        }
-    }
-
-    /**
-     * @return A string representing the given message ID.
-     */
-    private String messageIdAsString(int message) {
-        switch (message) {
-            case INJECT_NTP_TIME:
-                return "INJECT_NTP_TIME";
-            case REQUEST_LOCATION:
-                return "REQUEST_LOCATION";
-            case DOWNLOAD_PSDS_DATA:
-                return "DOWNLOAD_PSDS_DATA";
-            case REPORT_LOCATION:
-                return "REPORT_LOCATION";
-            case REPORT_SV_STATUS:
-                return "REPORT_SV_STATUS";
-            default:
-                return "<Unknown>";
+        boolean success = mHandler.post(() -> {
+            runnable.run();
+            mWakeLock.release();
+        });
+        if (!success) {
+            mWakeLock.release();
         }
     }
 
@@ -1476,7 +1407,7 @@
 
     @Override
     public void onReportLocation(boolean hasLatLong, Location location) {
-        sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
+        postWithWakeLockHeld(() -> handleReportLocation(hasLatLong, location));
     }
 
     @Override
@@ -1502,7 +1433,7 @@
 
     @Override
     public void onReportSvStatus(GnssStatus gnssStatus) {
-        sendMessage(REPORT_SV_STATUS, 0, gnssStatus);
+        postWithWakeLockHeld(() -> handleReportSvStatus(gnssStatus));
     }
 
     @Override
@@ -1512,7 +1443,7 @@
 
     @Override
     public void onRequestPsdsDownload(int psdsType) {
-        sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null);
+        postWithWakeLockHeld(() -> handleDownloadPsdsData(psdsType));
     }
 
     @Override
@@ -1558,7 +1489,7 @@
                     + ", isUserEmergency: "
                     + isUserEmergency);
         }
-        sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency);
+        postWithWakeLockHeld(() -> handleRequestLocation(independentFromGnss, isUserEmergency));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 21946ca..5de9cf3 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -331,7 +331,7 @@
         @Override
         public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
                 GnssCapabilities newCapabilities) {
-            long ident = Binder.clearCallingIdentity();
+            final long ident = Binder.clearCallingIdentity();
             try {
                 Intent intent = new Intent(LocationManager.ACTION_GNSS_CAPABILITIES_CHANGED)
                         .putExtra(LocationManager.EXTRA_GNSS_CAPABILITIES, newCapabilities)
diff --git a/services/core/java/com/android/server/location/injector/SystemDeviceStationaryHelper.java b/services/core/java/com/android/server/location/injector/SystemDeviceStationaryHelper.java
index 9874ecf..7369eac 100644
--- a/services/core/java/com/android/server/location/injector/SystemDeviceStationaryHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemDeviceStationaryHelper.java
@@ -41,7 +41,7 @@
     public void addListener(DeviceIdleInternal.StationaryListener listener) {
         Preconditions.checkState(mDeviceIdle != null);
 
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             mDeviceIdle.registerStationaryListener(listener);
         } finally {
@@ -53,7 +53,7 @@
     public void removeListener(DeviceIdleInternal.StationaryListener listener) {
         Preconditions.checkState(mDeviceIdle != null);
 
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             mDeviceIdle.unregisterStationaryListener(listener);
         } finally {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0bec09c..2efb239 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1620,7 +1620,7 @@
                             + PERMISSION);
         }
 
-        long identity = Binder.clearCallingIdentity();
+        final long identity = Binder.clearCallingIdentity();
         try {
             enforceFrpResolved();
             // When changing credential for profiles with unified challenge, some callers
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 42b7c9d3..8a33299 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -354,6 +354,12 @@
         }
     }
 
+    public void unregisterFileCleanupReceiver() {
+        if(mContext != null) {
+            mContext.unregisterReceiver(mFileCleanupReceiver);
+        }
+    }
+
     private static long safeParseLong(String fileName) {
         // AtomicFile will create copies of the numeric files with ".new" and ".bak"
         // over the course of its processing. If these files still exist on boot we need to clean
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index 6da898a..0aacd13 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -288,6 +288,7 @@
 
     private void disableHistory(NotificationHistoryDatabase userHistory, @UserIdInt int userId) {
         userHistory.disableHistory();
+        userHistory.unregisterFileCleanupReceiver();
 
         mUserPendingHistoryDisables.put(userId, false);
         mHistoryEnabled.put(userId, false);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d78fbdb..ca03f34 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2319,14 +2319,16 @@
 
         mUserProfiles.updateCache(getContext());
 
-        telephonyManager.listen(new PhoneStateListener() {
-            @Override
-            public void onCallStateChanged(int state, String incomingNumber) {
-                if (mCallState == state) return;
-                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
-                mCallState = state;
-            }
-        }, PhoneStateListener.LISTEN_CALL_STATE);
+        if (mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            telephonyManager.listen(new PhoneStateListener() {
+                @Override
+                public void onCallStateChanged(int state, String incomingNumber) {
+                    if (mCallState == state) return;
+                    if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
+                    mCallState = state;
+                }
+            }, PhoneStateListener.LISTEN_CALL_STATE);
+        }
 
         mSettingsObserver = new SettingsObserver(mHandler);
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f66cfa9..7a00b86 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -585,7 +585,8 @@
                     pw.println("null");
                 } else {
                     pw.print(val.getClass().getSimpleName());
-                    if (redact && (val instanceof CharSequence || val instanceof String)) {
+                    if (redact && (val instanceof CharSequence) && shouldRedactStringExtra(key)) {
+                        pw.print(String.format(" [length=%d]", ((CharSequence) val).length()));
                         // redact contents from bugreports
                     } else if (val instanceof Bitmap) {
                         pw.print(String.format(" (%dx%d)",
@@ -611,6 +612,19 @@
         }
     }
 
+    private boolean shouldRedactStringExtra(String key) {
+        if (key == null) return true;
+        switch (key) {
+            // none of these keys contain user-related information; they do not need to be redacted
+            case Notification.EXTRA_SUBSTITUTE_APP_NAME:
+            case Notification.EXTRA_TEMPLATE:
+            case "android.support.v4.app.extra.COMPAT_TEMPLATE":
+                return false;
+            default:
+                return true;
+        }
+    }
+
     @Override
     public final String toString() {
         return String.format(
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 0e2ff75..3ca6a0d 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -429,4 +429,14 @@
         return NotificationChannelLogger.getLoggingImportance(channel, importance);
     }
 
+    /**
+     * @param r NotificationRecord
+     * @return Whether the notification is a foreground service notification.
+     */
+    static boolean isForegroundService(@NonNull NotificationRecord r) {
+        if (r.getSbn() == null || r.getSbn().getNotification() == null) {
+            return false;
+        }
+        return (r.getSbn().getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
+    }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index 1a99fb0e..249910d 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -63,7 +63,12 @@
                 /* android.stats.sysui.NotificationImportance importance_asst = 19 */
                 r.getAssistantImportance(),
                 /* int32 assistant_hash = 20 */ p.getAssistantHash(),
-                /* float assistant_ranking_score = 21 */ r.getRankingScore()
+                /* float assistant_ranking_score = 21 */ r.getRankingScore(),
+                /* bool is_ongoing = 22 */ r.getSbn().isOngoing(),
+                /* bool is_foreground_service = 23 */
+                NotificationRecordLogger.isForegroundService(r),
+                /* optional int64 timeout_millis = 24 */
+                r.getSbn().getNotification().getTimeoutAfter()
         );
     }
 
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 3369dcd..3d328f8 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,7 +32,7 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.os.Binder;
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index 2851107..e0f1065 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -37,6 +37,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -461,8 +462,8 @@
                 }
 
                 // Obtaining array of certificates used for signing the installer package.
-                certs = installer.getSigningDetails().signatures;
-                pastCerts = installer.getSigningDetails().pastSigningCertificates;
+                certs = installer.getSigningDetails().getSignatures();
+                pastCerts = installer.getSigningDetails().getPastSigningCertificates();
             }
             if (certs == null || certs.length == 0 || certs[0] == null) {
                 Slog.e(TAG, "Can't obtain certificates.");
@@ -664,8 +665,7 @@
         Map<Integer, byte[]> contentDigests = null;
         try {
             contentDigests = ApkSignatureVerifier.verifySignaturesInternal(filePath,
-                    PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
-                    false).contentDigests;
+                    SignatureSchemeVersion.SIGNING_BLOCK_V2, /* verifyFull */ false).contentDigests;
         } catch (PackageParser.PackageParserException e) {
             if (!(e.getCause() instanceof SignatureNotFoundException)) {
                 Slog.e(TAG, "Signature verification error", e);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 1401fa9..56b77b5 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -17,8 +17,6 @@
 package com.android.server.pm;
 
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import static android.os.UserHandle.USER_ALL;
-import static android.os.UserHandle.USER_NULL;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -30,7 +28,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
+import android.content.pm.SigningDetails;
 import android.content.pm.UserInfo;
 import android.content.pm.parsing.component.ParsedComponent;
 import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -149,7 +147,7 @@
     private final OverlayReferenceMapper mOverlayReferenceMapper;
     private final StateProvider mStateProvider;
 
-    private PackageParser.SigningDetails mSystemSigningDetails;
+    private SigningDetails mSystemSigningDetails;
     private Set<String> mProtectedBroadcasts = new ArraySet<>();
 
     private final Object mCacheLock = new Object();
@@ -687,7 +685,7 @@
                 synchronized (mCacheLock) {
                     if (mShouldFilterCache != null) {
                         updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting,
-                                settings, users, USER_ALL, settings.size());
+                                settings, users, settings.size());
                         if (additionalChangedPackages != null) {
                             for (int index = 0; index < additionalChangedPackages.size(); index++) {
                                 String changedPackage = additionalChangedPackages.valueAt(index);
@@ -700,8 +698,7 @@
                                 }
 
                                 updateShouldFilterCacheForPackage(mShouldFilterCache, null,
-                                        changedPkgSetting, settings, users, USER_ALL,
-                                        settings.size());
+                                        changedPkgSetting, settings, users, settings.size());
                             }
                         }
                     } // else, rebuild entire cache when system is ready
@@ -833,57 +830,24 @@
             }
         }
     }
-    private void updateEntireShouldFilterCache() {
-        updateEntireShouldFilterCache(USER_ALL);
-    }
 
-    private void updateEntireShouldFilterCache(int subjectUserId) {
+    private void updateEntireShouldFilterCache() {
         mStateProvider.runWithState((settings, users) -> {
-            int userId = USER_NULL;
-            for (int u = 0; u < users.length; u++) {
-                if (subjectUserId == users[u].id) {
-                    userId = subjectUserId;
-                    break;
-                }
-            }
-            if (userId == USER_NULL) {
-                Slog.e(TAG, "We encountered a new user that isn't a member of known users, "
-                        + "updating the whole cache");
-                userId = USER_ALL;
-            }
             WatchedSparseBooleanMatrix cache =
-                    updateEntireShouldFilterCacheInner(settings, users, userId);
+                    updateEntireShouldFilterCacheInner(settings, users);
             synchronized (mCacheLock) {
-                if (userId != USER_ALL) {
-                    // if we're only updating a single user id, we need to copy over the prior
-                    // cached values for the other users.
-                    int[] uids = mShouldFilterCache.keys();
-                    for (int i = 0; i < uids.length; i++) {
-                        int uid1 = uids[i];
-                        if (UserHandle.getUserId(uid1) == userId) {
-                            continue;
-                        }
-                        for (int j = 0; j < uids.length; j++) {
-                            int uid2 = uids[j];
-                            if (UserHandle.getUserId(uid2) == userId) {
-                                continue;
-                            }
-                            cache.put(uid1, uid2, mShouldFilterCache.get(uid1, uid2));
-                        }
-                    }
-                }
                 mShouldFilterCache = cache;
             }
         });
     }
 
     private WatchedSparseBooleanMatrix updateEntireShouldFilterCacheInner(
-            ArrayMap<String, PackageSetting> settings, UserInfo[] users, int subjectUserId) {
+            ArrayMap<String, PackageSetting> settings, UserInfo[] users) {
         WatchedSparseBooleanMatrix cache =
                 new WatchedSparseBooleanMatrix(users.length * settings.size());
         for (int i = settings.size() - 1; i >= 0; i--) {
             updateShouldFilterCacheForPackage(cache,
-                    null /*skipPackage*/, settings.valueAt(i), settings, users, subjectUserId, i);
+                    null /*skipPackage*/, settings.valueAt(i), settings, users, i);
         }
         return cache;
     }
@@ -904,8 +868,8 @@
                     packagesCache.put(settings.keyAt(i), pkg);
                 }
             });
-            WatchedSparseBooleanMatrix cache = updateEntireShouldFilterCacheInner(
-                    settingsCopy, usersRef[0], USER_ALL);
+            WatchedSparseBooleanMatrix cache =
+                    updateEntireShouldFilterCacheInner(settingsCopy, usersRef[0]);
             boolean[] changed = new boolean[1];
             // We have a cache, let's make sure the world hasn't changed out from under us.
             mStateProvider.runWithState((settings, users) -> {
@@ -935,10 +899,10 @@
         });
     }
 
-    public void onUserCreated(int newUserId) {
+    public void onUsersChanged() {
         synchronized (mCacheLock) {
             if (mShouldFilterCache != null) {
-                updateEntireShouldFilterCache(newUserId);
+                updateEntireShouldFilterCache();
                 onChanged();
             }
         }
@@ -949,7 +913,7 @@
             if (mShouldFilterCache != null) {
                 mStateProvider.runWithState((settings, users) -> {
                     updateShouldFilterCacheForPackage(mShouldFilterCache, null /* skipPackage */,
-                            settings.get(packageName), settings, users, USER_ALL,
+                            settings.get(packageName), settings, users,
                             settings.size() /*maxIndex*/);
                 });
             }
@@ -958,7 +922,7 @@
 
     private void updateShouldFilterCacheForPackage(WatchedSparseBooleanMatrix cache,
             @Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String,
-            PackageSetting> allSettings, UserInfo[] allUsers, int subjectUserId, int maxIndex) {
+            PackageSetting> allSettings, UserInfo[] allUsers, int maxIndex) {
         for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) {
             PackageSetting otherSetting = allSettings.valueAt(i);
             if (subjectSetting.appId == otherSetting.appId) {
@@ -968,35 +932,26 @@
             if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) {
                 continue;
             }
-            if (subjectUserId == USER_ALL) {
-                for (int su = 0; su < allUsers.length; su++) {
-                    updateShouldFilterCacheForUser(cache, subjectSetting, allUsers, otherSetting,
-                            allUsers[su].id);
+            final int userCount = allUsers.length;
+            final int appxUidCount = userCount * allSettings.size();
+            for (int su = 0; su < userCount; su++) {
+                int subjectUser = allUsers[su].id;
+                for (int ou = 0; ou < userCount; ou++) {
+                    int otherUser = allUsers[ou].id;
+                    int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
+                    int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
+                    cache.put(subjectUid, otherUid,
+                            shouldFilterApplicationInternal(
+                                    subjectUid, subjectSetting, otherSetting, otherUser));
+                    cache.put(otherUid, subjectUid,
+                            shouldFilterApplicationInternal(
+                                    otherUid, otherSetting, subjectSetting, subjectUser));
                 }
-            } else {
-                updateShouldFilterCacheForUser(cache, subjectSetting, allUsers, otherSetting,
-                        subjectUserId);
             }
         }
     }
 
-    private void updateShouldFilterCacheForUser(WatchedSparseBooleanMatrix cache,
-            PackageSetting subjectSetting, UserInfo[] allUsers, PackageSetting otherSetting,
-            int subjectUserId) {
-        for (int ou = 0; ou < allUsers.length; ou++) {
-            int otherUser = allUsers[ou].id;
-            int subjectUid = UserHandle.getUid(subjectUserId, subjectSetting.appId);
-            int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
-            cache.put(subjectUid, otherUid,
-                    shouldFilterApplicationInternal(
-                            subjectUid, subjectSetting, otherSetting, otherUser));
-            cache.put(otherUid, subjectUid,
-                    shouldFilterApplicationInternal(
-                            otherUid, otherSetting, subjectSetting, subjectUserId));
-        }
-    }
-
-    private static boolean isSystemSigned(@NonNull PackageParser.SigningDetails sysSigningDetails,
+    private static boolean isSystemSigned(@NonNull SigningDetails sysSigningDetails,
             PackageSetting pkgSetting) {
         return pkgSetting.isSystem()
                 && pkgSetting.signatures.mSigningDetails.signaturesMatchExactly(sysSigningDetails);
@@ -1190,7 +1145,7 @@
                             continue;
                         }
                         updateShouldFilterCacheForPackage(mShouldFilterCache, setting.name,
-                                siblingSetting, settings, users, USER_ALL, settings.size());
+                                siblingSetting, settings, users, settings.size());
                     }
                 }
 
@@ -1207,7 +1162,7 @@
                             }
 
                             updateShouldFilterCacheForPackage(mShouldFilterCache, null,
-                                    changedPkgSetting, settings, users, USER_ALL, settings.size());
+                                    changedPkgSetting, settings, users, settings.size());
                         }
                     }
                 }
@@ -1332,20 +1287,6 @@
                 }
             }
 
-            // This package isn't technically installed and won't be written to settings, so we can
-            // treat it as filtered until it's available again.
-            final AndroidPackage targetPkg = targetPkgSetting.pkg;
-            if (targetPkg == null) {
-                if (DEBUG_LOGGING) {
-                    Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
-                }
-                return true;
-            }
-            if (targetPkg.isStaticSharedLibrary()) {
-                // not an app, this filtering takes place at a higher level
-                return false;
-            }
-            final String targetName = targetPkg.getPackageName();
             if (DEBUG_TRACING) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId");
             }
@@ -1388,6 +1329,21 @@
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
             }
+
+            // This package isn't technically installed and won't be written to settings, so we can
+            // treat it as filtered until it's available again.
+            final AndroidPackage targetPkg = targetPkgSetting.pkg;
+            if (targetPkg == null) {
+                if (DEBUG_LOGGING) {
+                    Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
+                }
+                return true;
+            }
+            if (targetPkg.isStaticSharedLibrary()) {
+                // not an app, this filtering takes place at a higher level
+                return false;
+            }
+
             try {
                 if (DEBUG_TRACING) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
@@ -1460,6 +1416,7 @@
                 if (DEBUG_TRACING) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
                 }
+                final String targetName = targetPkg.getPackageName();
                 if (callingSharedPkgSettings != null) {
                     int size = callingSharedPkgSettings.size();
                     for (int index = 0; index < size; index++) {
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3019439..fb68b23 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -178,6 +178,16 @@
                     .addDataType("*/*")
                     .build();
 
+    /** Pick images can be forwarded to parent user. */
+    private static final DefaultCrossProfileIntentFilter ACTION_PICK_IMAGES =
+            new DefaultCrossProfileIntentFilter.Builder(
+                    DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
+                    /* flags= */ 0,
+                    /* letsPersonalDataIntoProfile= */ true)
+                    .addAction(MediaStore.ACTION_PICK_IMAGES)
+                    .addCategory(Intent.CATEGORY_DEFAULT)
+                    .build();
+
     /** Open document intent can be forwarded to parent user. */
     private static final DefaultCrossProfileIntentFilter OPEN_DOCUMENT =
             new DefaultCrossProfileIntentFilter.Builder(
@@ -289,6 +299,7 @@
                 RECOGNIZE_SPEECH,
                 ACTION_PICK_RAW,
                 ACTION_PICK_DATA,
+                ACTION_PICK_IMAGES,
                 OPEN_DOCUMENT,
                 GET_CONTENT,
                 USB_DEVICE_ATTACHED,
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index bf323e7..affacbb 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -23,8 +23,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
+import android.content.pm.SigningDetails;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -412,14 +412,14 @@
             // into account but also allow the value from the old computation to avoid
             // data loss.
             if (pkg.getSigningDetails().checkCapability(currentCookieSha256,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
+                    SigningDetails.CertCapabilities.INSTALLED_DATA)) {
                 return;
             }
 
             // For backwards compatibility we accept match based on any signature, since we may have
             // recorded only the first for multiply-signed packages
-            final String[] signaturesSha256Digests =
-                    PackageUtils.computeSignaturesSha256Digests(pkg.getSigningDetails().signatures);
+            final String[] signaturesSha256Digests = PackageUtils.computeSignaturesSha256Digests(
+                    pkg.getSigningDetails().getSignatures());
             for (String s : signaturesSha256Digests) {
                 if (s.equals(currentCookieSha256)) {
                     return;
@@ -1305,8 +1305,8 @@
             // We prefer the modern computation procedure where all certs are taken
             // into account and delete the file derived via the legacy hash computation.
             File newCookieFile = computeInstantCookieFile(pkg.getPackageName(),
-                    PackageUtils.computeSignaturesSha256Digest(pkg.getSigningDetails().signatures),
-                    userId);
+                    PackageUtils.computeSignaturesSha256Digest(
+                            pkg.getSigningDetails().getSignatures()), userId);
             if (!pkg.getSigningDetails().hasSignatures()) {
                 Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!");
             }
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 34caaf5..fe74889 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -193,7 +193,7 @@
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Passed invalid package to keyset validation.");
         }
-        ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().publicKeys;
+        ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().getPublicKeys();
         if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Package has invalid signing-key-set.");
@@ -226,7 +226,7 @@
         PackageSetting ps = mPackages.get(pkg.getPackageName());
         Objects.requireNonNull(ps, "pkg: " + pkg.getPackageName()
                     + "does not have a corresponding entry in mPackages.");
-        addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().publicKeys);
+        addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().getPublicKeys());
         if (pkg.getKeySetMapping() != null) {
             addDefinedKeySetsToPackageLPw(ps, pkg.getKeySetMapping());
             if (pkg.getUpgradeKeySets() != null) {
@@ -371,7 +371,7 @@
         for (int i = 0; i < upgradeKeySets.length; i++) {
             Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
             if (upgradeSet != null
-                    && pkg.getSigningDetails().publicKeys.containsAll(upgradeSet)) {
+                    && pkg.getSigningDetails().getPublicKeys().containsAll(upgradeSet)) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d2ed08f..3b2517e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -254,7 +254,8 @@
         mSessionsDir.mkdirs();
 
         mApexManager = ApexManager.getInstance();
-        mStagingManager = new StagingManager(context, apexParserSupplier);
+        mStagingManager = new StagingManager(context, apexParserSupplier,
+                mInstallThread.getLooper());
 
         LocalServices.getService(SystemServiceManager.class).startService(
                 new Lifecycle(context, this));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index acc83cf..ec97200 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -46,9 +46,11 @@
 import static com.android.server.pm.PackageInstallerService.prepareStageDir;
 
 import android.Manifest;
+import android.annotation.AnyThread;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.WorkerThread;
 import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -82,8 +84,8 @@
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.SigningDetails;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.parsing.ApkLite;
 import android.content.pm.parsing.ApkLiteParseUtils;
@@ -263,6 +265,15 @@
     private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
     private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
 
+    /**
+     * The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link
+     * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#Q} before getting the
+     * target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared
+     * result will not trigger any user action in
+     * {@link #checkUserActionRequirement(PackageInstallerSession)}.
+     */
+    private static final int INVALID_TARGET_SDK_VERSION = Integer.MAX_VALUE;
+
     // TODO: enforce INSTALL_ALLOW_TEST
     // TODO: enforce INSTALL_ALLOW_DOWNGRADE
 
@@ -366,7 +377,7 @@
     @GuardedBy("mLock")
     private long mVersionCode;
     @GuardedBy("mLock")
-    private PackageParser.SigningDetails mSigningDetails;
+    private SigningDetails mSigningDetails;
     @GuardedBy("mLock")
     private SparseArray<PackageInstallerSession> mChildSessions = new SparseArray<>();
     @GuardedBy("mLock")
@@ -705,28 +716,22 @@
         }
 
         /**
-         * Notified by the staging manager that pre-reboot verification is about to start. The
-         * return value should be checked to decide whether it is OK to start pre-reboot
-         * verification. In the case of a destroyed session, {@code false} is returned and there is
-         * no need to start pre-reboot verification.
+         * Called when pre-reboot verification is about to start. This shouldn't be called
+         * on a destroyed session.
          */
-        @Override
-        public boolean notifyStartPreRebootVerification() {
+        private void notifyStartPreRebootVerification() {
             synchronized (mLock) {
+                Preconditions.checkState(!mDestroyed);
                 if (mInPreRebootVerification) {
                     throw new IllegalStateException("Pre-reboot verification has started");
                 }
-                if (mDestroyed) {
-                    return false;
-                }
                 mInPreRebootVerification = true;
-                return true;
             }
         }
 
         /**
-         * Notified by the staging manager that pre-reboot verification has ended. Now it is safe to
-         * clean up the session if {@link #abandon()} has been called previously.
+         * Notified by the staging manager or PIS that pre-reboot verification has ended.
+         * Now it is safe to clean up the session if {@link #abandon()} has been called previously.
          */
         @Override
         public void notifyEndPreRebootVerification() {
@@ -750,6 +755,7 @@
             assertCallerIsOwnerOrRootOrSystem();
             Preconditions.checkArgument(isCommitted());
             Preconditions.checkArgument(!mSessionApplied && !mSessionFailed);
+            notifyStartPreRebootVerification();
             verify();
         }
 
@@ -803,6 +809,12 @@
     @GuardedBy("mLock")
     private PackageLite mPackageLite;
 
+    /**
+     * Keep the target sdk of a validated apk.
+     */
+    @GuardedBy("mLock")
+    private int mValidatedTargetSdk = INVALID_TARGET_SDK_VERSION;
+
     private static final FileFilter sAddedApkFilter = new FileFilter() {
         @Override
         public boolean accept(File file) {
@@ -1735,6 +1747,7 @@
         mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
     }
 
+    @WorkerThread
     private void handleStreamValidateAndCommit() {
         PackageManagerException unrecoverableFailure = null;
         // This will track whether the session and any children were validated and are ready to
@@ -1984,6 +1997,7 @@
      * exception is thrown.
      * @throws PackageManagerException on an unrecoverable error.
      */
+    @WorkerThread
     private boolean streamValidateAndCommit() throws PackageManagerException {
         // TODO(patb): since the work done here for a parent session in a multi-package install is
         //             mostly superficial, consider splitting this method for the parent and
@@ -2101,9 +2115,7 @@
         if (isStaged()) {
             mStagedSession.setSessionFailed(
                     SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
-            // TODO(b/136257624): Remove this once all verification logic has been transferred out
-            //  of StagingManager.
-            mStagingManager.notifyVerificationComplete(mStagedSession);
+            mStagedSession.notifyEndPreRebootVerification();
         } else {
             // Dispatch message to remove session from PackageInstallerService.
             dispatchSessionFinished(error, msg, null);
@@ -2147,6 +2159,7 @@
      *                    immutable by the caller during the method call. Used to resolve child
      *                    sessions Ids to actual object reference.
      */
+    @AnyThread
     void onAfterSessionRead(SparseArray<PackageInstallerSession> allSessions) {
         synchronized (mLock) {
             // Resolve null values to actual object references
@@ -2232,6 +2245,63 @@
         }
     }
 
+    @WorkerThread
+    private static boolean checkUserActionRequirement(PackageInstallerSession session) {
+        if (session.isMultiPackage()) {
+            return false;
+        }
+
+        @UserActionRequirement int userActionRequirement = USER_ACTION_NOT_NEEDED;
+        // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
+        userActionRequirement = session.computeUserActionRequirement();
+        if (userActionRequirement == USER_ACTION_REQUIRED) {
+            session.sendPendingUserActionIntent();
+            return true;
+        }
+
+        if (!session.isApexSession() && userActionRequirement == USER_ACTION_PENDING_APK_PARSING) {
+            final int validatedTargetSdk;
+            synchronized (session.mLock) {
+                validatedTargetSdk = session.mValidatedTargetSdk;
+            }
+
+            if (validatedTargetSdk != INVALID_TARGET_SDK_VERSION
+                    && validatedTargetSdk < Build.VERSION_CODES.Q) {
+                session.sendPendingUserActionIntent();
+                return true;
+            }
+
+            if (session.params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED) {
+                if (!session.mSilentUpdatePolicy.isSilentUpdateAllowed(
+                        session.getInstallerPackageName(), session.getPackageName())) {
+                    // Fall back to the non-silent update if a repeated installation is invoked
+                    // within the throttle time.
+                    session.sendPendingUserActionIntent();
+                    return true;
+                }
+                session.mSilentUpdatePolicy.track(session.getInstallerPackageName(),
+                        session.getPackageName());
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Find out any session needs user action.
+     *
+     * @return true if the session set requires user action for the installation, otherwise false.
+     */
+    @WorkerThread
+    private boolean sendPendingUserActionIntentIfNeeded() {
+        synchronized (mLock) {
+            assertNotChildLocked("PackageInstallerSession#sendPendingUserActionIntentIfNeeded");
+        }
+
+        return sessionContains(PackageInstallerSession::checkUserActionRequirement);
+    }
+
+    @WorkerThread
     private void handleInstall() {
         if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) {
             DevicePolicyEventLogger
@@ -2240,6 +2310,17 @@
                     .write();
         }
 
+        /**
+         * Stops the installation of the whole session set if one session needs user action
+         * in its belong session set. When the user answers the yes,
+         * {@link #setPermissionsResult(boolean)} is called and then {@link #MSG_INSTALL} is
+         * handled to come back here to check again.
+         */
+        if (sendPendingUserActionIntentIfNeeded()) {
+            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.
@@ -2260,14 +2341,14 @@
         }
 
         if (params.isStaged) {
-            mStagingManager.commitSession(mStagedSession);
             // 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.
             dispatchSessionFinished(INSTALL_SUCCEEDED, "Session staged", null);
-            return;
-        }
 
-        verify();
+            mStagedSession.verifySession();
+        } else {
+            verify();
+        }
     }
 
     private void verify() {
@@ -2279,18 +2360,18 @@
         }
     }
 
+    private IntentSender getRemoteStatusReceiver() {
+        synchronized (mLock) {
+            return mRemoteStatusReceiver;
+        }
+    }
+
     private void verifyNonStaged()
             throws PackageManagerException {
         final PackageManagerService.VerificationParams verifyingSession =
                 prepareForVerification();
-        if (verifyingSession == null) {
-            return;
-        }
         if (isMultiPackage()) {
-            final List<PackageInstallerSession> childSessions;
-            synchronized (mLock) {
-                childSessions = getChildSessionsLocked();
-            }
+            final List<PackageInstallerSession> childSessions = getChildSessions();
             // Spot check to reject a non-staged multi package install of APEXes and APKs.
             if (!params.isStaged && containsApkSession()
                     && sessionContains(s -> s.isApexSession())) {
@@ -2307,20 +2388,14 @@
                 try {
                     final PackageManagerService.VerificationParams verifyingChildSession =
                             session.prepareForVerification();
-                    if (verifyingChildSession != null) {
-                        verifyingChildSessions.add(verifyingChildSession);
-                    }
+                    verifyingChildSessions.add(verifyingChildSession);
                 } catch (PackageManagerException e) {
                     failure = e;
                     success = false;
                 }
             }
             if (!success) {
-                final IntentSender statusReceiver;
-                synchronized (mLock) {
-                    statusReceiver = mRemoteStatusReceiver;
-                }
-                sendOnPackageInstalled(mContext, statusReceiver, sessionId,
+                sendOnPackageInstalled(mContext, getRemoteStatusReceiver(), sessionId,
                         isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,
                         failure.error, failure.getLocalizedMessage(), null);
                 return;
@@ -2348,10 +2423,7 @@
                     "Session should contain at least one apk session for installation");
         }
         if (isMultiPackage()) {
-            final List<PackageInstallerSession> childSessions;
-            synchronized (mLock) {
-                childSessions = getChildSessionsLocked();
-            }
+            final List<PackageInstallerSession> childSessions = getChildSessions();
             List<PackageManagerService.InstallParams> installingChildSessions =
                     new ArrayList<>(childSessions.size());
             boolean success = true;
@@ -2370,11 +2442,7 @@
                 }
             }
             if (!success) {
-                final IntentSender statusReceiver;
-                synchronized (mLock) {
-                    statusReceiver = mRemoteStatusReceiver;
-                }
-                sendOnPackageInstalled(mContext, statusReceiver, sessionId,
+                sendOnPackageInstalled(mContext, getRemoteStatusReceiver(), sessionId,
                         isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,
                         failure.error, failure.getLocalizedMessage(), null);
                 return;
@@ -2390,23 +2458,11 @@
      * {@link PackageManagerService.VerificationParams} representing this new staged state or null
      * in case permissions need to be requested before verification can proceed.
      */
-    @Nullable
+    @NonNull
     private PackageManagerService.VerificationParams prepareForVerification()
             throws PackageManagerException {
         assertNotLocked("makeSessionActive");
 
-        @UserActionRequirement
-        int userActionRequirement = USER_ACTION_NOT_NEEDED;
-        // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
-        if (!params.isMultiPackage) {
-            userActionRequirement = computeUserActionRequirement();
-            if (userActionRequirement == USER_ACTION_REQUIRED) {
-                sendPendingUserActionIntent();
-                return null;
-            } // else, we'll wait until we parse to determine if we need to
-        }
-
-        boolean silentUpdatePolicyEnforceable = false;
         synchronized (mLock) {
             if (mRelinquished) {
                 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
@@ -2423,36 +2479,16 @@
             PackageLite result = parseApkLite();
             if (result != null) {
                 mPackageLite = result;
-                synchronized (mProgressLock) {
-                    mInternalProgress = 0.5f;
-                    computeProgressLocked(true);
-                }
-
-                extractNativeLibraries(
-                        mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());
-
-                if (userActionRequirement == USER_ACTION_PENDING_APK_PARSING) {
-                    if (result.getTargetSdk() < Build.VERSION_CODES.Q) {
-                        sendPendingUserActionIntent();
-                        return null;
+                if (!isApexSession()) {
+                    synchronized (mProgressLock) {
+                        mInternalProgress = 0.5f;
+                        computeProgressLocked(true);
                     }
-                    if (params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED) {
-                        silentUpdatePolicyEnforceable = true;
-                    }
+
+                    extractNativeLibraries(
+                            mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());
                 }
             }
-        }
-        if (silentUpdatePolicyEnforceable) {
-            if (!mSilentUpdatePolicy.isSilentUpdateAllowed(
-                    getInstallerPackageName(), getPackageName())) {
-                // Fall back to the non-silent update if a repeated installation is invoked within
-                // the throttle time.
-                sendPendingUserActionIntent();
-                return null;
-            }
-            mSilentUpdatePolicy.track(getInstallerPackageName(), getPackageName());
-        }
-        synchronized (mLock) {
             return makeVerificationParamsLocked();
         }
     }
@@ -2465,11 +2501,7 @@
         intent.setPackage(mPm.getPackageInstallerPackageName());
         intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
 
-        final IntentSender statusReceiver;
-        synchronized (mLock) {
-            statusReceiver = mRemoteStatusReceiver;
-        }
-        sendOnUserActionRequired(mContext, statusReceiver, sessionId, intent);
+        sendOnUserActionRequired(mContext, getRemoteStatusReceiver(), sessionId, intent);
 
         // Commit was keeping session marked as active until now; release
         // that extra refcount so session appears idle.
@@ -2479,73 +2511,77 @@
     /**
      * Prepares staged directory with any inherited APKs and returns the parsed package.
      */
+    @GuardedBy("mLock")
     @Nullable
     private PackageLite parseApkLite() throws PackageManagerException {
 
 
-        // TODO(b/136257624): Some logic in this if block probably belongs in
-        //  makeInstallParams().
-        if (!isMultiPackage() && !isApexSession()) {
-            Objects.requireNonNull(mPackageName);
-            Objects.requireNonNull(mSigningDetails);
-            Objects.requireNonNull(mResolvedBaseFile);
+        if (isMultiPackage()) {
+            return null;
+        }
+        Objects.requireNonNull(mPackageName);
+        Objects.requireNonNull(mSigningDetails);
+        Objects.requireNonNull(mResolvedBaseFile);
 
-            // If we haven't already parsed, inherit any packages and native libraries from existing
-            // install that haven't been overridden.
-            if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
-                try {
-                    final List<File> fromFiles = mResolvedInheritedFiles;
-                    final File toDir = stageDir;
+        // Inherit any packages and native libraries from existing install that
+        // haven't been overridden.
+        if (!isApexSession() && params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+            try {
+                final List<File> fromFiles = mResolvedInheritedFiles;
+                final File toDir = stageDir;
 
-                    if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
-                    if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
-                        throw new IllegalStateException("mInheritedFilesBase == null");
-                    }
-
-                    if (isLinkPossible(fromFiles, toDir)) {
-                        if (!mResolvedInstructionSets.isEmpty()) {
-                            final File oatDir = new File(toDir, "oat");
-                            createOatDirs(mResolvedInstructionSets, oatDir);
-                        }
-                        // pre-create lib dirs for linking if necessary
-                        if (!mResolvedNativeLibPaths.isEmpty()) {
-                            for (String libPath : mResolvedNativeLibPaths) {
-                                // "/lib/arm64" -> ["lib", "arm64"]
-                                final int splitIndex = libPath.lastIndexOf('/');
-                                if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
-                                    Slog.e(TAG,
-                                            "Skipping native library creation for linking due"
-                                                    + " to invalid path: " + libPath);
-                                    continue;
-                                }
-                                final String libDirPath = libPath.substring(1, splitIndex);
-                                final File libDir = new File(toDir, libDirPath);
-                                if (!libDir.exists()) {
-                                    NativeLibraryHelper.createNativeLibrarySubdir(libDir);
-                                }
-                                final String archDirPath = libPath.substring(splitIndex + 1);
-                                NativeLibraryHelper.createNativeLibrarySubdir(
-                                        new File(libDir, archDirPath));
-                            }
-                        }
-                        linkFiles(fromFiles, toDir, mInheritedFilesBase);
-                    } else {
-                        // TODO: this should delegate to DCS so the system process
-                        // avoids holding open FDs into containers.
-                        copyFiles(fromFiles, toDir);
-                    }
-                } catch (IOException e) {
-                    throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                            "Failed to inherit existing install", e);
+                if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
+                if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
+                    throw new IllegalStateException("mInheritedFilesBase == null");
                 }
+
+                if (isLinkPossible(fromFiles, toDir)) {
+                    if (!mResolvedInstructionSets.isEmpty()) {
+                        final File oatDir = new File(toDir, "oat");
+                        createOatDirs(mResolvedInstructionSets, oatDir);
+                    }
+                    // pre-create lib dirs for linking if necessary
+                    if (!mResolvedNativeLibPaths.isEmpty()) {
+                        for (String libPath : mResolvedNativeLibPaths) {
+                            // "/lib/arm64" -> ["lib", "arm64"]
+                            final int splitIndex = libPath.lastIndexOf('/');
+                            if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
+                                Slog.e(TAG,
+                                        "Skipping native library creation for linking due"
+                                                + " to invalid path: " + libPath);
+                                continue;
+                            }
+                            final String libDirPath = libPath.substring(1, splitIndex);
+                            final File libDir = new File(toDir, libDirPath);
+                            if (!libDir.exists()) {
+                                NativeLibraryHelper.createNativeLibrarySubdir(libDir);
+                            }
+                            final String archDirPath = libPath.substring(splitIndex + 1);
+                            NativeLibraryHelper.createNativeLibrarySubdir(
+                                    new File(libDir, archDirPath));
+                        }
+                    }
+                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
+                } else {
+                    // TODO: this should delegate to DCS so the system process
+                    // avoids holding open FDs into containers.
+                    copyFiles(fromFiles, toDir);
+                }
+            } catch (IOException e) {
+                throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+                        "Failed to inherit existing install", e);
             }
+        }
+
+        if (!isApexSession()) {
             // For mode inherit existing, it would link/copy existing files to stage dir in the
             // above block. Therefore, we need to parse the complete package in stage dir here.
-            // Besides, PackageLite may be null for staged sessions that don't complete pre-reboot
-            // verification.
+            // Besides, PackageLite may be null for staged sessions that don't complete
+            // pre-reboot verification.
             return getOrParsePackageLiteLocked(stageDir, /* flags */ 0);
+        } else {
+            return getOrParsePackageLiteLocked(mResolvedBaseFile, /* flags */ 0);
         }
-        return null;
     }
 
     @GuardedBy("mLock")
@@ -2586,25 +2622,16 @@
 
         mRelinquished = true;
 
-        // TODO(b/169375643): Remove this workaround once b/161121612 is fixed.
-        PackageInstaller.SessionParams copiedParams = params.copy();
-        if (params.isStaged) {
-            // This is called by the pre-reboot verification. Don't enable rollback here since
-            // it has been enabled when pre-reboot verification starts.
-            copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
-        }
-        return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
+        return mPm.new VerificationParams(user, stageDir, localObserver, params,
                 mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
     }
 
     private void onVerificationComplete() {
-        // Staged sessions will be installed later during boot
+        // APK verification is done. Continue the installation depending on whether it is a
+        // staged session or not. For a staged session, we will hand it over to the staging
+        // manager to complete the installation.
         if (isStaged()) {
-            // TODO(b/136257624): Remove this once all verification logic has been transferred out
-            //  of StagingManager.
-            mStagingManager.notifyPreRebootVerification_Apk_Complete(mStagedSession);
-            // TODO(b/136257624): We also need to destroy internals for verified staged session,
-            //  otherwise file descriptors are never closed for verified staged session until reboot
+            mStagingManager.commitSession(mStagedSession);
             return;
         }
 
@@ -2854,6 +2881,8 @@
             mPackageName = apk.getPackageName();
             mVersionCode = apk.getLongVersionCode();
         }
+
+        mSigningDetails = apk.getSigningDetails();
     }
 
     /**
@@ -2872,11 +2901,11 @@
     @GuardedBy("mLock")
     private PackageLite validateApkInstallLocked() throws PackageManagerException {
         ApkLite baseApk = null;
-        PackageLite packageLite = null;
+        final PackageLite packageLite;
         mPackageLite = null;
         mPackageName = null;
         mVersionCode = -1;
-        mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
+        mSigningDetails = SigningDetails.UNKNOWN;
 
         mResolvedBaseFile = null;
         mResolvedStagedFiles.clear();
@@ -2939,7 +2968,7 @@
                 mPackageName = apk.getPackageName();
                 mVersionCode = apk.getLongVersionCode();
             }
-            if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+            if (mSigningDetails == SigningDetails.UNKNOWN) {
                 mSigningDetails = apk.getSigningDetails();
             }
 
@@ -2994,7 +3023,7 @@
                 mPackageName = pkgInfo.packageName;
                 mVersionCode = pkgInfo.getLongVersionCode();
             }
-            if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+            if (mSigningDetails == SigningDetails.UNKNOWN) {
                 mSigningDetails = unsafeGetCertsWithoutVerification(
                         pkgInfo.applicationInfo.sourceDir);
             }
@@ -3054,7 +3083,7 @@
             packageLite = existing;
             assertPackageConsistentLocked("Existing", existing.getPackageName(),
                     existing.getLongVersionCode());
-            final PackageParser.SigningDetails signingDetails =
+            final SigningDetails signingDetails =
                     unsafeGetCertsWithoutVerification(existing.getBaseApkPath());
             if (!mSigningDetails.signaturesMatchExactly(signingDetails)) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -3179,6 +3208,11 @@
                 mIncrementalFileStorages.disallowReadLogs();
             }
         }
+
+        // {@link #sendPendingUserActionIntentIfNeeded} needs to use
+        // {@link PackageLite#getTargetSdk()}
+        mValidatedTargetSdk = packageLite.getTargetSdk();
+
         return packageLite;
     }
 
@@ -3394,11 +3428,11 @@
         }
     }
 
-    private PackageParser.SigningDetails unsafeGetCertsWithoutVerification(String path)
+    private SigningDetails unsafeGetCertsWithoutVerification(String path)
             throws PackageManagerException {
         try {
             return ApkSignatureVerifier.unsafeGetCertsWithoutVerification(path,
-                    PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+                    SigningDetails.SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Couldn't obtain signatures from APK : " + path);
@@ -3590,8 +3624,13 @@
             // Mark and kick off another install pass
             synchronized (mLock) {
                 mPermissionsManuallyAccepted = true;
-                mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
             }
+
+            PackageInstallerSession root =
+                    (hasParentSessionId())
+                            ? mSessionProvider.getSession(getParentSessionId())
+                            : this;
+            root.mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
         } else {
             destroyInternal();
             dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
@@ -3877,11 +3916,7 @@
                         }
                         case IDataLoaderStatusListener.DATA_LOADER_UNAVAILABLE: {
                             // Don't fail or commit the session. Allow caller to commit again.
-                            final IntentSender statusReceiver;
-                            synchronized (mLock) {
-                                statusReceiver = mRemoteStatusReceiver;
-                            }
-                            sendPendingStreaming(mContext, statusReceiver, sessionId,
+                            sendPendingStreaming(mContext, getRemoteStatusReceiver(), sessionId,
                                     "DataLoader unavailable");
                             break;
                         }
@@ -3895,11 +3930,8 @@
                 } catch (RemoteException e) {
                     // In case of streaming failure we don't want to fail or commit the session.
                     // Just return from this method and allow caller to commit again.
-                    final IntentSender statusReceiver;
-                    synchronized (mLock) {
-                        statusReceiver = mRemoteStatusReceiver;
-                    }
-                    sendPendingStreaming(mContext, statusReceiver, sessionId, e.getMessage());
+                    sendPendingStreaming(mContext, getRemoteStatusReceiver(), sessionId,
+                            e.getMessage());
                 }
             }
         };
@@ -4168,18 +4200,13 @@
     }
 
     private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras) {
-        final IntentSender statusReceiver;
-        final String packageName;
-        synchronized (mLock) {
-            statusReceiver = mRemoteStatusReceiver;
-            packageName = mPackageName;
-        }
+        final IntentSender statusReceiver = getRemoteStatusReceiver();
         if (statusReceiver != null) {
             // Execute observer.onPackageInstalled on different thread as we don't want callers
             // inside the system server have to worry about catching the callbacks while they are
             // calling into the session
             final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = packageName;
+            args.arg1 = getPackageName();
             args.arg2 = msg;
             args.arg3 = extras;
             args.arg4 = statusReceiver;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 889785d..8090fa7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -95,7 +95,7 @@
 import static android.content.pm.PackageManager.TYPE_UNKNOWN;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
 import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
-import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
+import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
 import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
 import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
@@ -149,6 +149,7 @@
 import android.app.ApplicationPackageManager;
 import android.app.BroadcastOptions;
 import android.app.IActivityManager;
+import android.app.PendingIntent;
 import android.app.ResourcesManager;
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SecurityLog;
@@ -161,6 +162,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IIntentReceiver;
+import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -212,8 +214,6 @@
 import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails;
-import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.PackagePartitions;
 import android.content.pm.PackagePartitions.SystemPartition;
 import android.content.pm.PackageStats;
@@ -228,6 +228,8 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.SigningInfo;
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.TestUtilityService;
@@ -1356,7 +1358,6 @@
         public DefaultAppProvider defaultAppProvider;
         public DexManager dexManager;
         public List<ScanPartition> dirsToScanAsSystem;
-        public @Nullable String documenterPackage;
         public boolean factoryTest;
         public ArrayMap<String, FeatureInfo> availableFeatures;
         public Handler handler;
@@ -1705,7 +1706,6 @@
     final @Nullable String mStorageManagerPackage;
     final @Nullable String mDefaultTextClassifierPackage;
     final @Nullable String mSystemTextClassifierPackageName;
-    final @Nullable String mDocumenterPackage;
     final @Nullable String mConfiguratorPackage;
     final @Nullable String mAppPredictionServicePackage;
     final @Nullable String mIncidentReportApproverPackage;
@@ -6988,7 +6988,6 @@
         mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage;
         mRetailDemoPackage = testParams.retailDemoPackage;
         mRecentsPackage = testParams.recentsPackage;
-        mDocumenterPackage = testParams.documenterPackage;
         mConfiguratorPackage = testParams.configuratorPackage;
         mAppPredictionServicePackage = testParams.appPredictionServicePackage;
         mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
@@ -7587,7 +7586,6 @@
 
             mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName();
             mSystemTextClassifierPackageName = getSystemTextClassifierPackageName();
-            mDocumenterPackage = getDocumenterPackageName();
             mConfiguratorPackage = getDeviceConfiguratorPackageName();
             mAppPredictionServicePackage = getAppPredictionServicePackageName();
             mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
@@ -9783,7 +9781,8 @@
         if (p2SigningDetails == null) {
             return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
         }
-        int result = compareSignatures(p1SigningDetails.signatures, p2SigningDetails.signatures);
+        int result = compareSignatures(p1SigningDetails.getSignatures(),
+                p2SigningDetails.getSignatures());
         if (result == PackageManager.SIGNATURE_MATCH) {
             return result;
         }
@@ -9793,11 +9792,11 @@
         if (p1SigningDetails.hasPastSigningCertificates()
                 || p2SigningDetails.hasPastSigningCertificates()) {
             Signature[] p1Signatures = p1SigningDetails.hasPastSigningCertificates()
-                    ? new Signature[]{p1SigningDetails.pastSigningCertificates[0]}
-                    : p1SigningDetails.signatures;
+                    ? new Signature[]{p1SigningDetails.getPastSigningCertificates()[0]}
+                    : p1SigningDetails.getSignatures();
             Signature[] p2Signatures = p2SigningDetails.hasPastSigningCertificates()
-                    ? new Signature[]{p2SigningDetails.pastSigningCertificates[0]}
-                    : p2SigningDetails.signatures;
+                    ? new Signature[]{p2SigningDetails.getPastSigningCertificates()[0]}
+                    : p2SigningDetails.getSignatures();
             result = compareSignatures(p1Signatures, p2Signatures);
         }
         return result;
@@ -9841,7 +9840,7 @@
         final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mLock) {
-            final PackageParser.SigningDetails signingDetails;
+            final SigningDetails signingDetails;
             final Object obj = mSettings.getSettingLPr(appId);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
@@ -10135,7 +10134,22 @@
         if (getInstantAppPackageName(getCallingUid()) != null) {
             return EmptyArray.STRING;
         }
-        return mPermissionManager.getAppOpPermissionPackages(permissionName);
+        final int callingUid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(callingUid);
+
+        final ArraySet<String> packageNames = new ArraySet(
+                mPermissionManager.getAppOpPermissionPackages(permissionName));
+        synchronized (mLock) {
+            for (int i = packageNames.size() - 1; i >= 0; i--) {
+                final String packageName = packageNames.valueAt(i);
+                if (!shouldFilterApplicationLocked(mSettings.getPackageLPr(packageName),
+                        callingUid, callingUserId)) {
+                    continue;
+                }
+                packageNames.removeAt(i);
+            }
+        }
+        return packageNames.toArray(new String[packageNames.size()]);
     }
 
     @Override
@@ -11879,14 +11893,14 @@
                 && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
                 && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
-            if (ps.signatures.mSigningDetails.signatures != null
-                    && ps.signatures.mSigningDetails.signatures.length != 0
-                    && ps.signatures.mSigningDetails.signatureSchemeVersion
+            if (ps.signatures.mSigningDetails.getSignatures() != null
+                    && ps.signatures.mSigningDetails.getSignatures().length != 0
+                    && ps.signatures.mSigningDetails.getSignatureSchemeVersion()
                             != SignatureSchemeVersion.UNKNOWN) {
                 // Optimization: reuse the existing cached signing data
                 // if the package appears to be unchanged.
                 parsedPackage.setSigningDetails(
-                        new PackageParser.SigningDetails(ps.signatures.mSigningDetails));
+                        new SigningDetails(ps.signatures.mSigningDetails));
                 return;
             }
 
@@ -12190,10 +12204,10 @@
 
             if (!parsedPackage.getSigningDetails()
                     .checkCapability(pkgSetting.signatures.mSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                    SigningDetails.CertCapabilities.INSTALLED_DATA)
                             && !pkgSetting.signatures.mSigningDetails.checkCapability(
                                     parsedPackage.getSigningDetails(),
-                                    PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
+                                    SigningDetails.CertCapabilities.ROLLBACK)) {
                 logCriticalInfo(Log.WARN,
                         "System package signature mismatch;"
                         + " name: " + pkgSetting.name);
@@ -13494,9 +13508,9 @@
                         // For apps targeting O MR1 we require explicit enumeration of all certs.
                         final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
                                 ? PackageUtils.computeSignaturesSha256Digests(
-                                libPkg.signatures)
+                                libPkg.getSignatures())
                                 : PackageUtils.computeSignaturesSha256Digests(
-                                        new Signature[]{libPkg.signatures[0]});
+                                        new Signature[]{libPkg.getSignatures()[0]});
 
                         // Take a shortcut if sizes don't match. Note that if an app doesn't
                         // target O we don't parse the "additional-certificate" tags similarly
@@ -13837,8 +13851,9 @@
                 // priv-apps.
                 synchronized (mLock) {
                     PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
-                    if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
-                            pkg.getSigningDetails().signatures)
+                    if ((compareSignatures(
+                            platformPkgSetting.signatures.mSigningDetails.getSignatures(),
+                            pkg.getSigningDetails().getSignatures())
                             != PackageManager.SIGNATURE_MATCH)) {
                         scanFlags |= SCAN_AS_PRIVILEGED;
                     }
@@ -14677,8 +14692,8 @@
         parsedPackage.setSignedWithPlatformKey(
                 (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())
                         || (platformPkg != null && compareSignatures(
-                        platformPkg.getSigningDetails().signatures,
-                        parsedPackage.getSigningDetails().signatures
+                        platformPkg.getSigningDetails().getSignatures(),
+                        parsedPackage.getSigningDetails().getSignatures()
                 ) == PackageManager.SIGNATURE_MATCH))
         );
 
@@ -14974,7 +14989,7 @@
                     // Exempt SharedUsers signed with the platform key.
                     PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
                     if (!comparePackageSignatures(platformPkgSetting,
-                            pkg.getSigningDetails().signatures)) {
+                            pkg.getSigningDetails().getSignatures())) {
                         throw new PackageManagerException("Apps that share a user with a " +
                                 "privileged app must themselves be marked as privileged. " +
                                 pkg.getPackageName() + " shares privileged user " +
@@ -15022,7 +15037,7 @@
                         final PackageSetting platformPkgSetting =
                                 mSettings.getPackageLPr("android");
                         if (!comparePackageSignatures(platformPkgSetting,
-                                pkg.getSigningDetails().signatures)) {
+                                pkg.getSigningDetails().getSignatures())) {
                             throw new PackageManagerException("Overlay "
                                     + pkg.getPackageName()
                                     + " must target Q or later, "
@@ -15042,7 +15057,7 @@
                                 mSettings.getPackageLPr(pkg.getOverlayTarget());
                         if (targetPkgSetting != null) {
                             if (!comparePackageSignatures(targetPkgSetting,
-                                    pkg.getSigningDetails().signatures)) {
+                                    pkg.getSigningDetails().getSignatures())) {
                                 // check reference signature
                                 if (mOverlayConfigSignaturePackage == null) {
                                     throw new PackageManagerException("Overlay "
@@ -15054,7 +15069,7 @@
                                 final PackageSetting refPkgSetting =
                                         mSettings.getPackageLPr(mOverlayConfigSignaturePackage);
                                 if (!comparePackageSignatures(refPkgSetting,
-                                        pkg.getSigningDetails().signatures)) {
+                                        pkg.getSigningDetails().getSignatures())) {
                                     throw new PackageManagerException("Overlay "
                                             + pkg.getPackageName() + " signed with a different "
                                             + "certificate than both the reference package and "
@@ -15073,7 +15088,8 @@
                 int minSignatureSchemeVersion =
                         ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
                                 pkg.getTargetSdkVersion());
-                if (pkg.getSigningDetails().signatureSchemeVersion < minSignatureSchemeVersion) {
+                if (pkg.getSigningDetails().getSignatureSchemeVersion()
+                        < minSignatureSchemeVersion) {
                     throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                             "No signature found in package of version " + minSignatureSchemeVersion
                                     + " or newer for package " + pkg.getPackageName());
@@ -16883,7 +16899,7 @@
             final AndroidPackage pkg = mPackages.get(verifierInfo.packageName);
             if (pkg == null) {
                 return -1;
-            } else if (pkg.getSigningDetails().signatures.length != 1) {
+            } else if (pkg.getSigningDetails().getSignatures().length != 1) {
                 Slog.i(TAG, "Verifier package " + verifierInfo.packageName
                         + " has more than one signature; ignoring");
                 return -1;
@@ -16897,7 +16913,7 @@
 
             final byte[] expectedPublicKey;
             try {
-                final Signature verifierSig = pkg.getSigningDetails().signatures[0];
+                final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
                 final PublicKey publicKey = verifierSig.getPublicKey();
                 expectedPublicKey = publicKey.getEncoded();
             } catch (CertificateException e) {
@@ -17161,9 +17177,10 @@
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     callerSignature =
-                            ((SharedUserSetting)obj).signatures.mSigningDetails.signatures;
+                            ((SharedUserSetting) obj).signatures.mSigningDetails.getSignatures();
                 } else if (obj instanceof PackageSetting) {
-                    callerSignature = ((PackageSetting)obj).signatures.mSigningDetails.signatures;
+                    callerSignature =
+                            ((PackageSetting) obj).signatures.mSigningDetails.getSignatures();
                 } else {
                     throw new SecurityException("Bad object " + obj + " for uid " + callingUid);
                 }
@@ -17175,7 +17192,7 @@
             // not signed with the same cert as the caller.
             if (installerPackageSetting != null) {
                 if (compareSignatures(callerSignature,
-                        installerPackageSetting.signatures.mSigningDetails.signatures)
+                        installerPackageSetting.signatures.mSigningDetails.getSignatures())
                         != PackageManager.SIGNATURE_MATCH) {
                     throw new SecurityException(
                             "Caller does not have same cert as new installer package "
@@ -17192,7 +17209,7 @@
 
             if (targetInstallerPkgSetting != null) {
                 if (compareSignatures(callerSignature,
-                        targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+                        targetInstallerPkgSetting.signatures.mSigningDetails.getSignatures())
                         != PackageManager.SIGNATURE_MATCH) {
                     throw new SecurityException(
                             "Caller does not have same cert as old installer package "
@@ -17760,7 +17777,7 @@
         final String[] grantedRuntimePermissions;
         final List<String> whitelistedRestrictedPermissions;
         final int autoRevokePermissionsMode;
-        final PackageParser.SigningDetails signingDetails;
+        final SigningDetails signingDetails;
         final int installReason;
         final int mInstallScenario;
         @Nullable MultiPackageInstallParams mParentInstallParams;
@@ -17784,7 +17801,7 @@
             this.grantedRuntimePermissions = null;
             this.whitelistedRestrictedPermissions = null;
             this.autoRevokePermissionsMode = MODE_DEFAULT;
-            this.signingDetails = PackageParser.SigningDetails.UNKNOWN;
+            this.signingDetails = SigningDetails.UNKNOWN;
             this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
             this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
             this.forceQueryableOverride = false;
@@ -18079,7 +18096,7 @@
         @NonNull final InstallSource installSource;
         final String packageAbiOverride;
         final VerificationInfo verificationInfo;
-        final PackageParser.SigningDetails signingDetails;
+        final SigningDetails signingDetails;
         @Nullable MultiPackageVerificationParams mParentVerificationParams;
         final long requiredInstalledVersionCode;
         final int mDataLoaderType;
@@ -18122,13 +18139,6 @@
         }
 
         public void handleStartCopy() {
-            if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
-                // Apex packages get verified in StagingManager currently.
-                // TODO(b/136257624): Move apex verification logic out of StagingManager
-                mRet = INSTALL_SUCCEEDED;
-                return;
-            }
-
             PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                     mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
 
@@ -18140,7 +18150,10 @@
             // Perform package verification and enable rollback (unless we are simply moving the
             // package).
             if (!origin.existing) {
-                sendApkVerificationRequest(pkgLite);
+                if ((installFlags & PackageManager.INSTALL_APEX) == 0) {
+                    // TODO(b/182426975): treat APEX as APK when APK verification is concerned
+                    sendApkVerificationRequest(pkgLite);
+                }
                 if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                     sendEnableRollbackRequest();
                 }
@@ -18187,28 +18200,23 @@
             // it will not miss the broadcast.
             enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
 
-            mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
-                    android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
-                    new BroadcastReceiver() {
-                        @Override
-                        public void onReceive(Context context, Intent intent) {
-                            // the duration to wait for rollback to be enabled, in millis
-                            long rollbackTimeout = DeviceConfig.getLong(
-                                    DeviceConfig.NAMESPACE_ROLLBACK,
-                                    PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
-                                    DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
-                            if (rollbackTimeout < 0) {
-                                rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
-                            }
-                            final Message msg = mHandler.obtainMessage(
-                                    ENABLE_ROLLBACK_TIMEOUT);
-                            msg.arg1 = enableRollbackToken;
-                            msg.arg2 = mSessionId;
-                            mHandler.sendMessageDelayed(msg, rollbackTimeout);
-                        }
-                    }, null, 0, null, null);
+            mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
+                    android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
 
             mWaitForEnableRollbackToComplete = true;
+
+            // the duration to wait for rollback to be enabled, in millis
+            long rollbackTimeout = DeviceConfig.getLong(
+                    DeviceConfig.NAMESPACE_ROLLBACK,
+                    PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+                    DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
+            if (rollbackTimeout < 0) {
+                rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
+            }
+            final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
+            msg.arg1 = enableRollbackToken;
+            msg.arg2 = mSessionId;
+            mHandler.sendMessageDelayed(msg, rollbackTimeout);
         }
 
         /**
@@ -18301,7 +18309,7 @@
             final boolean isVerificationEnabled = isVerificationEnabled(
                     pkgLite, verifierUser.getIdentifier(), installFlags, installerUid);
             final boolean isV4Signed =
-                    (signingDetails.signatureSchemeVersion == SIGNING_BLOCK_V4);
+                    (signingDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
             final boolean isIncrementalInstall =
                     (mDataLoaderType == DataLoaderType.INCREMENTAL);
             // NOTE: We purposefully skip verification for only incremental installs when there's
@@ -18532,7 +18540,7 @@
         /** If non-null, drop an async trace when the install completes */
         final String traceMethod;
         final int traceCookie;
-        final PackageParser.SigningDetails signingDetails;
+        final SigningDetails signingDetails;
         final int installReason;
         final int mInstallScenario;
         final boolean forceQueryableOverride;
@@ -18670,7 +18678,7 @@
         FileInstallArgs(String codePath, String[] instructionSets) {
             super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
                     null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
-                    PackageParser.SigningDetails.UNKNOWN,
+                    SigningDetails.UNKNOWN,
                     PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
                     false, DataLoaderType.NONE);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
@@ -19526,11 +19534,11 @@
                     // the signatures on the first package scanned for the shared user (i.e. if the
                     // signaturesChanged state hasn't been initialized yet in SharedUserSetting).
                     if (signatureCheckPs.sharedUser != null) {
-                        final Signature[] sharedUserSignatures =
-                                signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures;
+                        final Signature[] sharedUserSignatures = signatureCheckPs.sharedUser
+                                .signatures.mSigningDetails.getSignatures();
                         if (signatureCheckPs.sharedUser.signaturesChanged != null
                                 && compareSignatures(sharedUserSignatures,
-                                parsedPackage.getSigningDetails().signatures)
+                                parsedPackage.getSigningDetails().getSignatures())
                                         != PackageManager.SIGNATURE_MATCH) {
                             if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
                                 // Mismatched signatures is an error and silently skipping system
@@ -19934,7 +19942,7 @@
                     if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
                         continue;
                     }
-                    if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {
+                    if (args.signingDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) {
                         continue;
                     }
                     // For incremental installs, we bypass the verifier prior to install. Now
@@ -20339,11 +20347,11 @@
             // older certificate with which the current is ok with sharing permissions
             if (sourceSigningDetails.checkCapability(
                     parsedPackage.getSigningDetails(),
-                    PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+                    SigningDetails.CertCapabilities.PERMISSION)) {
                 return true;
             } else if (parsedPackage.getSigningDetails().checkCapability(
                     sourceSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+                    SigningDetails.CertCapabilities.PERMISSION)) {
                 // the scanned package checks out, has signing certificate rotation
                 // history, and is newer; bring it over
                 synchronized (mLock) {
@@ -20458,7 +20466,7 @@
 
         try {
             // either use what we've been given or parse directly from the APK
-            if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+            if (args.signingDetails != SigningDetails.UNKNOWN) {
                 parsedPackage.setSigningDetails(args.signingDetails);
             } else {
                 parsedPackage.setSigningDetails(ParsingPackageUtils.getSigningDetails(
@@ -20468,7 +20476,7 @@
             throw new PrepareFailure("Failed collect during installPackageLI", e);
         }
 
-        if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion
+        if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion()
                 < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
             Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
                     + " is not signed with at least APK Signature Scheme v2");
@@ -23557,25 +23565,6 @@
                 getPackageFromComponentString(R.string.config_defaultRotationResolverService));
     }
 
-    private @Nullable String getDocumenterPackageName() {
-        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        intent.setType("*/*");
-        final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
-
-        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, resolvedType,
-                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
-                        | MATCH_DISABLED_COMPONENTS,
-                UserHandle.myUserId());
-        if (matches.size() == 1) {
-            return matches.get(0).getComponentInfo().packageName;
-        } else {
-            Slog.e(TAG, "There should probably be exactly one documenter; found "
-                    + matches.size() + ": matches=" + matches);
-            return null;
-        }
-    }
-
     @Nullable
     private String getDeviceConfiguratorPackageName() {
         return ensureSystemPackageName(mContext.getString(
@@ -23655,10 +23644,10 @@
         final AndroidPackage androidPkg = mPackages.get(predefinedPkgName);
         if (androidPkg != null) {
             final SigningDetails signingDetail = androidPkg.getSigningDetails();
-            if (signingDetail != null && signingDetail.signatures != null) {
+            if (signingDetail != null && signingDetail.getSignatures() != null) {
                 try {
                     final MessageDigest msgDigest = MessageDigest.getInstance("SHA-256");
-                    for (Signature signature : signingDetail.signatures) {
+                    for (Signature signature : signingDetail.getSignatures()) {
                         if (TextUtils.equals(predefinedSignature,
                                 HexEncoding.encodeToString(msgDigest.digest(
                                         signature.toByteArray()), false))) {
@@ -26504,7 +26493,7 @@
         synchronized (mLock) {
             scheduleWritePackageRestrictionsLocked(userId);
             scheduleWritePackageListLocked(userId);
-            mAppsFilter.onUserCreated(userId);
+            mAppsFilter.onUsersChanged();
         }
     }
 
@@ -26704,6 +26693,11 @@
 
     private int verifyReplacingVersionCode(PackageInfoLite pkgLite,
             long requiredInstalledVersionCode, int installFlags) {
+        if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+            return verifyReplacingVersionCodeForApex(
+                    pkgLite, requiredInstalledVersionCode, installFlags);
+        }
+
         String packageName = pkgLite.packageName;
         synchronized (mLock) {
             // Package which currently owns the data that the new package will own if installed.
@@ -26750,6 +26744,40 @@
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
+    private int verifyReplacingVersionCodeForApex(PackageInfoLite pkgLite,
+            long requiredInstalledVersionCode, int installFlags) {
+        String packageName = pkgLite.packageName;
+
+        final PackageInfo activePackage = mApexManager.getPackageInfo(packageName,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
+        if (activePackage == null) {
+            Slog.w(TAG, "Attempting to install new APEX package " + packageName);
+            return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+        }
+
+        final long activeVersion = activePackage.getLongVersionCode();
+        if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST
+                && activeVersion != requiredInstalledVersionCode) {
+            Slog.w(TAG, "Installed version of APEX package " + packageName
+                    + " does not match required. Active version: " + activeVersion
+                    + " required: " + requiredInstalledVersionCode);
+            return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
+        }
+
+        final boolean isAppDebuggable = (activePackage.applicationInfo.flags
+                & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+        final long newVersionCode = pkgLite.getLongVersionCode();
+        if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, isAppDebuggable)
+                && newVersionCode < activeVersion) {
+            Slog.w(TAG, "Downgrade of APEX package " + packageName
+                    + " is not allowed. Active version: " + activeVersion
+                    + " attempted: " + newVersionCode);
+            return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+        }
+
+        return PackageManager.INSTALL_SUCCEEDED;
+    }
+
     /**
      * Check and throw if the given before/after packages would be considered a
      * downgrade.
@@ -27078,7 +27106,7 @@
             }
             return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails())
                     || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(),
-                    PackageParser.SigningDetails.CertCapabilities.PERMISSION);
+                    SigningDetails.CertCapabilities.PERMISSION);
         }
 
         @Override
@@ -27255,8 +27283,6 @@
                             mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
                 case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
                     return filterOnlySystemPackages(mRequiredPermissionControllerPackage);
-                case PackageManagerInternal.PACKAGE_DOCUMENTER:
-                    return filterOnlySystemPackages(mDocumenterPackage);
                 case PackageManagerInternal.PACKAGE_CONFIGURATOR:
                     return filterOnlySystemPackages(mConfiguratorPackage);
                 case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
@@ -28933,6 +28959,56 @@
         }
     }
 
+    @Override
+    public IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
+            String featureId, int userId) throws RemoteException {
+        Objects.requireNonNull(packageName);
+        final int callingUid = Binder.getCallingUid();
+        enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+                false /* checkShell */, "get launch intent sender for package");
+        final int packageUid = getPackageUid(callingPackage, 0 /* flags */, userId);
+        if (!UserHandle.isSameApp(callingUid, packageUid)) {
+            throw new SecurityException("getLaunchIntentSenderForPackage() from calling uid: "
+                    + callingUid + " does not own package: " + callingPackage);
+        }
+
+        // Using the same implementation with the #getLaunchIntentForPackage to get the ResolveInfo.
+        // Pass the resolveForStart as true in queryIntentActivities to skip the app filtering.
+        final Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(Intent.CATEGORY_INFO);
+        intentToResolve.setPackage(packageName);
+        String resolvedType = intentToResolve.resolveTypeIfNeeded(mContext.getContentResolver());
+        List<ResolveInfo> ris = queryIntentActivitiesInternal(intentToResolve, resolvedType,
+                0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId,
+                true /* resolveForStart */, false /* allowDynamicSplits */);
+        if (ris == null || ris.size() <= 0) {
+            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
+            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+            intentToResolve.setPackage(packageName);
+            resolvedType = intentToResolve.resolveTypeIfNeeded(mContext.getContentResolver());
+            ris = queryIntentActivitiesInternal(intentToResolve, resolvedType,
+                    0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId,
+                    true /* resolveForStart */, false /* allowDynamicSplits */);
+        }
+
+        final Intent intent = new Intent(intentToResolve);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        // For the case of empty result, no component name is assigned into the intent. A
+        // non-launchable IntentSender which contains the failed intent is created. The
+        // SendIntentException is thrown if the IntentSender#sendIntent is invoked.
+        if (ris != null && !ris.isEmpty()) {
+            intent.setClassName(ris.get(0).activityInfo.packageName,
+                    ris.get(0).activityInfo.name);
+        }
+        final IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature(
+                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                featureId, null /* token */, null /* resultWho */,
+                1 /* requestCode */, new Intent[] { intent },
+                resolvedType != null ? new String[] { resolvedType } : null,
+                PendingIntent.FLAG_IMMUTABLE, null /* bOptions */, userId);
+        return new IntentSender(target);
+    }
+
     private static class TempUserState {
         public final int enabledState;
         @Nullable
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 8b5abf3..5fdb57d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -34,9 +34,9 @@
 import android.content.Intent;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
 import android.content.pm.parsing.result.ParseResult;
@@ -499,9 +499,9 @@
      */
     public static boolean comparePackageSignatures(PackageSetting pkgSetting,
             Signature[] signatures) {
-        return pkgSetting.signatures.mSigningDetails
-                == PackageParser.SigningDetails.UNKNOWN
-                || compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, signatures)
+        final SigningDetails signingDetails = pkgSetting.signatures.mSigningDetails;
+        return signingDetails == SigningDetails.UNKNOWN
+                || compareSignatures(signingDetails.getSignatures(), signatures)
                 == PackageManager.SIGNATURE_MATCH;
     }
 
@@ -512,13 +512,13 @@
      * system upgrade) and {@code scannedSigs} will be in the newer format.
      */
     private static boolean matchSignaturesCompat(String packageName,
-            PackageSignatures packageSignatures, PackageParser.SigningDetails parsedSignatures) {
+            PackageSignatures packageSignatures, SigningDetails parsedSignatures) {
         ArraySet<Signature> existingSet = new ArraySet<Signature>();
-        for (Signature sig : packageSignatures.mSigningDetails.signatures) {
+        for (Signature sig : packageSignatures.mSigningDetails.getSignatures()) {
             existingSet.add(sig);
         }
         ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
-        for (Signature sig : parsedSignatures.signatures) {
+        for (Signature sig : parsedSignatures.getSignatures()) {
             try {
                 Signature[] chainSignatures = sig.getChainSignatures();
                 for (Signature chainSig : chainSignatures) {
@@ -547,9 +547,9 @@
 
     private static boolean matchSignaturesRecover(
             String packageName,
-            PackageParser.SigningDetails existingSignatures,
-            PackageParser.SigningDetails parsedSignatures,
-            @PackageParser.SigningDetails.CertCapabilities int flags) {
+            SigningDetails existingSignatures,
+            SigningDetails parsedSignatures,
+            @SigningDetails.CertCapabilities int flags) {
         String msg = null;
         try {
             if (parsedSignatures.checkCapabilityRecover(existingSignatures, flags)) {
@@ -576,10 +576,10 @@
             PackageSetting disabledPkgSetting) {
         if (pkgSetting.signatures.mSigningDetails.checkCapability(
                 disabledPkgSetting.signatures.mSigningDetails,
-                PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                SigningDetails.CertCapabilities.INSTALLED_DATA)
                 || disabledPkgSetting.signatures.mSigningDetails.checkCapability(
                 pkgSetting.signatures.mSigningDetails,
-                PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
+                SigningDetails.CertCapabilities.ROLLBACK)) {
             return true;
         } else {
             logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " +
@@ -623,19 +623,19 @@
      * @throws PackageManagerException if the signatures did not match.
      */
     public static boolean verifySignatures(PackageSetting pkgSetting,
-            PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
+            PackageSetting disabledPkgSetting, SigningDetails parsedSignatures,
             boolean compareCompat, boolean compareRecover, boolean isRollback)
             throws PackageManagerException {
         final String packageName = pkgSetting.name;
         boolean compatMatch = false;
-        if (pkgSetting.signatures.mSigningDetails.signatures != null) {
+        if (pkgSetting.signatures.mSigningDetails.getSignatures() != null) {
             // Already existing package. Make sure signatures match
             boolean match = parsedSignatures.checkCapability(
                     pkgSetting.signatures.mSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                    SigningDetails.CertCapabilities.INSTALLED_DATA)
                             || pkgSetting.signatures.mSigningDetails.checkCapability(
                                     parsedSignatures,
-                                    PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
+                                    SigningDetails.CertCapabilities.ROLLBACK);
             if (!match && compareCompat) {
                 match = matchSignaturesCompat(packageName, pkgSetting.signatures,
                         parsedSignatures);
@@ -646,12 +646,12 @@
                         packageName,
                         pkgSetting.signatures.mSigningDetails,
                         parsedSignatures,
-                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                        SigningDetails.CertCapabilities.INSTALLED_DATA)
                                 || matchSignaturesRecover(
                                         packageName,
                                         parsedSignatures,
                                         pkgSetting.signatures.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
+                                        SigningDetails.CertCapabilities.ROLLBACK);
             }
 
             if (!match && isApkVerificationForced(disabledPkgSetting)) {
@@ -674,7 +674,7 @@
         // Check for shared user signatures
         if (pkgSetting.getSharedUser() != null
                 && pkgSetting.getSharedUser().signatures.mSigningDetails
-                        != PackageParser.SigningDetails.UNKNOWN) {
+                        != SigningDetails.UNKNOWN) {
 
             // Already existing package. Make sure signatures match.  In case of signing certificate
             // rotation, the packages with newer certs need to be ok with being sharedUserId with
@@ -684,10 +684,10 @@
             boolean match =
                     parsedSignatures.checkCapability(
                             pkgSetting.getSharedUser().signatures.mSigningDetails,
-                            PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
+                            SigningDetails.CertCapabilities.SHARED_USER_ID)
                     || pkgSetting.getSharedUser().signatures.mSigningDetails.checkCapability(
                             parsedSignatures,
-                            PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
+                            SigningDetails.CertCapabilities.SHARED_USER_ID);
             // Special case: if the sharedUserId capability check failed it could be due to this
             // being the only package in the sharedUserId so far and the lineage being updated to
             // deny the sharedUserId capability of the previous key in the lineage.
@@ -704,11 +704,11 @@
                         matchSignaturesRecover(packageName,
                                 pkgSetting.getSharedUser().signatures.mSigningDetails,
                                 parsedSignatures,
-                                PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
+                                SigningDetails.CertCapabilities.SHARED_USER_ID)
                         || matchSignaturesRecover(packageName,
                                 parsedSignatures,
                                 pkgSetting.getSharedUser().signatures.mSigningDetails,
-                                PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
+                                SigningDetails.CertCapabilities.SHARED_USER_ID);
                 compatMatch |= match;
             }
             if (!match) {
@@ -729,13 +729,13 @@
                     if (packageName.equals(shUidPkgSetting.name)) {
                         continue;
                     }
-                    PackageParser.SigningDetails shUidSigningDetails =
+                    SigningDetails shUidSigningDetails =
                             shUidPkgSetting.getSigningDetails();
                     // The capability check only needs to be performed against the package if it is
                     // signed with a key that is in the lineage of the package being installed.
                     if (parsedSignatures.hasAncestor(shUidSigningDetails)) {
                         if (!parsedSignatures.checkCapability(shUidSigningDetails,
-                                PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)) {
+                                SigningDetails.CertCapabilities.SHARED_USER_ID)) {
                             throw new PackageManagerException(
                                     INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                                     "Package " + packageName
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 731d41c..e2443c1 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -27,9 +27,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IncrementalStatesInfo;
 import android.content.pm.PackageManager.UninstallReason;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.overlay.OverlayPaths;
 import android.os.PersistableBundle;
@@ -217,10 +217,10 @@
     }
 
     public Signature[] getSignatures() {
-        return signatures.mSigningDetails.signatures;
+        return signatures.mSigningDetails.getSignatures();
     }
 
-    public PackageParser.SigningDetails getSigningDetails() {
+    public SigningDetails getSigningDetails() {
         return signatures.mSigningDetails;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
index 394cdee..a1e5051 100644
--- a/services/core/java/com/android/server/pm/PackageSignatures.java
+++ b/services/core/java/com/android/server/pm/PackageSignatures.java
@@ -17,9 +17,9 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.util.Log;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
@@ -35,40 +35,41 @@
 
 class PackageSignatures {
 
-    @NonNull PackageParser.SigningDetails mSigningDetails;
+    @NonNull SigningDetails mSigningDetails;
 
     PackageSignatures(PackageSignatures orig) {
-        if (orig != null && orig.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) {
-            mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails);
+        if (orig != null && orig.mSigningDetails != SigningDetails.UNKNOWN) {
+            mSigningDetails = new SigningDetails(orig.mSigningDetails);
         } else {
-            mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
+            mSigningDetails = SigningDetails.UNKNOWN;
         }
     }
 
-    PackageSignatures(PackageParser.SigningDetails signingDetails) {
+    PackageSignatures(SigningDetails signingDetails) {
         mSigningDetails = signingDetails;
     }
 
     PackageSignatures() {
-        mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
+        mSigningDetails = SigningDetails.UNKNOWN;
     }
 
     void writeXml(TypedXmlSerializer serializer, String tagName,
             ArrayList<Signature> writtenSignatures) throws IOException {
-        if (mSigningDetails.signatures == null) {
+        if (mSigningDetails.getSignatures() == null) {
             return;
         }
         serializer.startTag(null, tagName);
-        serializer.attributeInt(null, "count", mSigningDetails.signatures.length);
-        serializer.attributeInt(null, "schemeVersion", mSigningDetails.signatureSchemeVersion);
-        writeCertsListXml(serializer, writtenSignatures, mSigningDetails.signatures, false);
+        serializer.attributeInt(null, "count", mSigningDetails.getSignatures().length);
+        serializer.attributeInt(null, "schemeVersion", mSigningDetails.getSignatureSchemeVersion());
+        writeCertsListXml(serializer, writtenSignatures, mSigningDetails.getSignatures(), false);
 
         // if we have past signer certificate information, write it out
-        if (mSigningDetails.pastSigningCertificates != null) {
+        if (mSigningDetails.getPastSigningCertificates() != null) {
             serializer.startTag(null, "pastSigs");
-            serializer.attributeInt(null, "count", mSigningDetails.pastSigningCertificates.length);
+            serializer.attributeInt(null, "count",
+                    mSigningDetails.getPastSigningCertificates().length);
             writeCertsListXml(serializer, writtenSignatures,
-                    mSigningDetails.pastSigningCertificates, true);
+                    mSigningDetails.getPastSigningCertificates(), true);
             serializer.endTag(null, "pastSigs");
         }
         serializer.endTag(null, tagName);
@@ -106,8 +107,7 @@
 
     void readXml(TypedXmlPullParser parser, ArrayList<Signature> readSignatures)
             throws IOException, XmlPullParserException {
-        PackageParser.SigningDetails.Builder builder =
-                new PackageParser.SigningDetails.Builder();
+        SigningDetails.Builder builder = new SigningDetails.Builder();
 
         final int count = parser.getAttributeInt(null, "count", -1);
         if (count == -1) {
@@ -142,13 +142,13 @@
             PackageManagerService.reportSettingsProblem(Log.WARN,
                     "Error in package manager settings: <sigs> "
                             + "unable to convert certificate(s) to public key(s).");
-            mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
+            mSigningDetails = SigningDetails.UNKNOWN;
         }
     }
 
     private int readCertsListXml(TypedXmlPullParser parser, ArrayList<Signature> readSignatures,
             ArrayList<Signature> signatures, int count, boolean isPastSigs,
-            PackageParser.SigningDetails.Builder builder)
+            SigningDetails.Builder builder)
             throws IOException, XmlPullParserException {
         int pos = 0;
 
@@ -306,25 +306,25 @@
         buf.append("PackageSignatures{");
         buf.append(Integer.toHexString(System.identityHashCode(this)));
         buf.append(" version:");
-        buf.append(mSigningDetails.signatureSchemeVersion);
+        buf.append(mSigningDetails.getSignatureSchemeVersion());
         buf.append(", signatures:[");
-        if (mSigningDetails.signatures != null) {
-            for (int i = 0; i < mSigningDetails.signatures.length; i++) {
+        if (mSigningDetails.getSignatures() != null) {
+            for (int i = 0; i < mSigningDetails.getSignatures().length; i++) {
                 if (i > 0) buf.append(", ");
                 buf.append(Integer.toHexString(
-                        mSigningDetails.signatures[i].hashCode()));
+                        mSigningDetails.getSignatures()[i].hashCode()));
             }
         }
         buf.append("]");
         buf.append(", past signatures:[");
-        if (mSigningDetails.pastSigningCertificates != null) {
-            for (int i = 0; i < mSigningDetails.pastSigningCertificates.length; i++) {
+        if (mSigningDetails.getPastSigningCertificates() != null) {
+            for (int i = 0; i < mSigningDetails.getPastSigningCertificates().length; i++) {
                 if (i > 0) buf.append(", ");
                 buf.append(Integer.toHexString(
-                        mSigningDetails.pastSigningCertificates[i].hashCode()));
+                        mSigningDetails.getPastSigningCertificates()[i].hashCode()));
                 buf.append(" flags: ");
-                buf.append(
-                        Integer.toHexString(mSigningDetails.pastSigningCertificates[i].getFlags()));
+                buf.append(Integer.toHexString(
+                        mSigningDetails.getPastSigningCertificates()[i].getFlags()));
             }
         }
         buf.append("]}");
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c5fbfba..de45466 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -19,8 +19,8 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
@@ -79,7 +79,7 @@
 
     /**
      * Allows opt-in to the latest targetSdkVersion enforced changes without changing target SDK.
-     * Turning this change off for an app targeting the latest SDK is a no-op.
+     * Turning this change off for an app targeting the latest SDK or higher is a no-op.
      *
      * <p>Has no effect for apps using shared user id.
      *
@@ -92,7 +92,7 @@
     /**
      * This change gates apps access to untrusted_app_R-targetSDK SELinux domain. Allows opt-in
      * to R targetSdkVersion enforced changes without changing target SDK. Turning this change
-     * off for an app targeting S is a no-op.
+     * off for an app targeting {@code >= android.os.Build.VERSION_CODES.R} is a no-op.
      *
      * <p>Has no effect for apps using shared user id.
      *
@@ -364,7 +364,7 @@
         }
         final ApplicationInfo appInfo = pkg.toAppInfoWithoutState();
         if (compatibility.isChangeEnabledInternal(SELINUX_LATEST_CHANGES, appInfo)) {
-            return android.os.Build.VERSION_CODES.S;
+            return Math.max(android.os.Build.VERSION_CODES.S, pkg.getTargetSdkVersion());
         } else if (compatibility.isChangeEnabledInternal(SELINUX_R_CHANGES, appInfo)) {
             return Math.max(android.os.Build.VERSION_CODES.R, pkg.getTargetSdkVersion());
         }
@@ -577,7 +577,7 @@
         // Check for exact signature matches across all certs.
         Signature[] certs = mCerts.toArray(new Signature[0]);
         if (pkg.getSigningDetails() != SigningDetails.UNKNOWN
-                && !Signature.areExactMatch(certs, pkg.getSigningDetails().signatures)) {
+                && !Signature.areExactMatch(certs, pkg.getSigningDetails().getSignatures())) {
 
             // certs aren't exact match, but the package may have rotated from the known system cert
             if (certs.length > 1 || !pkg.getSigningDetails().hasCertificate(certs[0])) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 26aebbc..f38c48c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1169,12 +1169,13 @@
     // by that time.
     void insertPackageSettingLPw(PackageSetting p, AndroidPackage pkg) {
         // Update signatures if needed.
-        if (p.signatures.mSigningDetails.signatures == null) {
+        if (p.signatures.mSigningDetails.getSignatures() == null) {
             p.signatures.mSigningDetails = pkg.getSigningDetails();
         }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
-        if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) {
+        if (p.sharedUser != null
+                && p.sharedUser.signatures.mSigningDetails.getSignatures() == null) {
             p.sharedUser.signatures.mSigningDetails = pkg.getSigningDetails();
         }
         addPackageSettingLPw(p, p.sharedUser);
@@ -2966,6 +2967,17 @@
             mReadMessages.append("Error reading: " + e.toString());
             PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
             Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+        } finally {
+            if (!mVersion.containsKey(StorageManager.UUID_PRIVATE_INTERNAL)) {
+                Slog.wtf(PackageManagerService.TAG,
+                        "No internal VersionInfo found in settings, using current.");
+                findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
+            }
+            if (!mVersion.containsKey(StorageManager.UUID_PRIMARY_PHYSICAL)) {
+                Slog.wtf(PackageManagerService.TAG,
+                        "No external VersionInfo found in settings, using current.");
+                findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
+            }
         }
 
         // If the build is setup to drop runtime permissions
@@ -4490,7 +4502,7 @@
             pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
             pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isUsesNonSdkApi());
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
-            final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion;
+            final int apkSigningVersion = pkg.getSigningDetails().getSignatureSchemeVersion();
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
             pw.print(prefix); pw.print("  applicationInfo=");
             pw.println(pkg.toAppInfoToString());
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index fcbf40e..945df5d 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -86,6 +86,7 @@
 import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.text.TextUtils;
@@ -598,6 +599,7 @@
         if (DEBUG_PROCSTATE) {
             Slog.d(TAG, "onUidStateChanged: uid=" + uid + " state=" + procState);
         }
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "shortcutHandleOnUidStateChanged");
         synchronized (mLock) {
             mUidState.put(uid, procState);
 
@@ -608,6 +610,7 @@
                 mUidLastForegroundElapsedTime.put(uid, injectElapsedRealtime());
             }
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
     private boolean isProcessStateForeground(int processState) {
@@ -703,10 +706,12 @@
         // or anything.
         final long start = getStatStartTime();
         injectRunOnNewThread(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "shortcutHandleUnlockUser");
             synchronized (mLock) {
                 logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
                 getUserShortcutsLocked(userId);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         });
     }
 
@@ -715,6 +720,7 @@
         if (DEBUG || DEBUG_REBOOT) {
             Slog.d(TAG, "handleStopUser: user=" + userId);
         }
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "shortcutHandleStopUser");
         synchronized (mLock) {
             unloadUserLocked(userId);
 
@@ -722,6 +728,7 @@
                 mUnlockedUsers.put(userId, false);
             }
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
     @GuardedBy("mLock")
@@ -1192,6 +1199,7 @@
             return;
         }
         try {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "shortcutSaveDirtyInfo");
             synchronized (mLock) {
                 for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
                     final int userId = mDirtyUserIds.get(i);
@@ -1205,6 +1213,8 @@
             }
         } catch (Exception e) {
             wtf("Exception in saveDirtyInfo", e);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index c842ff1..4bdddf1 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -28,7 +28,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
@@ -36,8 +35,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.SigningDetails;
-import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
+import android.content.pm.SigningDetails;
+import android.content.pm.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
@@ -82,6 +81,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
@@ -114,6 +114,8 @@
     @GuardedBy("mSuccessfulStagedSessionIds")
     private final List<Integer> mSuccessfulStagedSessionIds = new ArrayList<>();
 
+    private final CompletableFuture<Void> mBootCompleted = new CompletableFuture<>();
+
     interface StagedSession {
         boolean isMultiPackage();
         boolean isApexSession();
@@ -138,25 +140,28 @@
         boolean hasParentSessionId();
         long getCommittedMillis();
         void abandon();
-        boolean notifyStartPreRebootVerification();
         void notifyEndPreRebootVerification();
         void verifySession();
     }
 
-    StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier) {
-        this(context, packageParserSupplier, ApexManager.getInstance());
+    StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier, Looper looper) {
+        this(context, packageParserSupplier, ApexManager.getInstance(), looper);
     }
 
     @VisibleForTesting
     StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier,
             ApexManager apexManager) {
+        this(context, packageParserSupplier, apexManager, BackgroundThread.get().getLooper());
+    }
+
+    StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier,
+            ApexManager apexManager, Looper looper) {
         mContext = context;
         mPackageParserSupplier = packageParserSupplier;
 
         mApexManager = apexManager;
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mPreRebootVerificationHandler = new PreRebootVerificationHandler(
-                BackgroundThread.get().getLooper());
+        mPreRebootVerificationHandler = new PreRebootVerificationHandler(looper);
 
         if (mFailureReasonFile.exists()) {
             try (BufferedReader reader = new BufferedReader(new FileReader(mFailureReasonFile))) {
@@ -231,7 +236,7 @@
         final SigningDetails existingSigningDetails;
         try {
             existingSigningDetails = ApkSignatureVerifier.verify(
-                existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
+                    existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
             throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                     "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
@@ -296,15 +301,6 @@
                 throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                         "Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
             }
-            final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
-                    ApexManager.MATCH_ACTIVE_PACKAGE);
-            if (activePackage == null) {
-                Slog.w(TAG, "Attempting to install new APEX package " + packageInfo.packageName);
-                throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                        "It is forbidden to install new APEX packages.");
-            }
-            checkRequiredVersionCode(session, activePackage);
-            checkDowngrade(session, activePackage, packageInfo);
             result.add(packageInfo);
             apexPackageNames.add(packageInfo.packageName);
         }
@@ -327,40 +323,6 @@
                 "Could not find rollback id for commit session: " + sessionId);
     }
 
-    private void checkRequiredVersionCode(final StagedSession session,
-            final PackageInfo activePackage) throws PackageManagerException {
-        if (session.sessionParams().requiredInstalledVersionCode
-                == PackageManager.VERSION_CODE_HIGHEST) {
-            return;
-        }
-        final long activeVersion = activePackage.applicationInfo.longVersionCode;
-        if (activeVersion != session.sessionParams().requiredInstalledVersionCode) {
-            throw new PackageManagerException(
-                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "Installed version of APEX package " + activePackage.packageName
-                            + " does not match required. Active version: " + activeVersion
-                            + " required: " + session.sessionParams().requiredInstalledVersionCode);
-        }
-    }
-
-    private void checkDowngrade(final StagedSession session,
-            final PackageInfo activePackage, final PackageInfo newPackage)
-            throws PackageManagerException {
-        final long activeVersion = activePackage.applicationInfo.longVersionCode;
-        final long newVersionCode = newPackage.applicationInfo.longVersionCode;
-        final boolean isAppDebuggable = (activePackage.applicationInfo.flags
-                & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-        final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
-                session.sessionParams().installFlags, isAppDebuggable);
-        if (activeVersion > newVersionCode && !allowsDowngrade) {
-            throw new PackageManagerException(
-                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "Downgrade of APEX package " + newPackage.packageName
-                            + " is not allowed. Active version: " + activeVersion
-                            + " attempted: " + newVersionCode);
-        }
-    }
-
     // Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
     private void abortCheckpoint(String failureReason, boolean supportsCheckpoint,
             boolean needsCheckpoint) {
@@ -869,7 +831,8 @@
             } else if (!session.isSessionReady()) {
                 // The framework got restarted before the pre-reboot verification could complete,
                 // restart the verification.
-                mPreRebootVerificationHandler.startPreRebootVerification(session);
+                Slog.i(TAG, "Restart verification for session=" + session.sessionId());
+                mBootCompleted.thenRun(() -> session.verifySession());
                 StagedSession session2 = sessions.set(j - 1, session);
                 sessions.set(i, session2);
                 j--;
@@ -1053,7 +1016,7 @@
 
     @VisibleForTesting
     void onBootCompletedBroadcastReceived() {
-        mPreRebootVerificationHandler.readyToStart();
+        mBootCompleted.complete(null);
         BackgroundThread.getExecutor().execute(() -> logFailedApexSessionsIfNecessary());
     }
 
@@ -1094,24 +1057,7 @@
         return session;
     }
 
-    // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
-    //  verification logic is extracted out of StagingManager into PMS, we can remove
-    //  this.
-    void notifyVerificationComplete(StagedSession session) {
-        mPreRebootVerificationHandler.onPreRebootVerificationComplete(session);
-    }
-
-    // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
-    //  verification logic is extracted out of StagingManager into PMS, we can remove
-    //  this.
-    void notifyPreRebootVerification_Apk_Complete(@NonNull StagedSession session) {
-        mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(session);
-    }
-
     private final class PreRebootVerificationHandler extends Handler {
-        // Hold sessions before handler gets ready to do the verification.
-        private List<StagedSession> mPendingSessions;
-        private boolean mIsReady;
 
         PreRebootVerificationHandler(Looper looper) {
             super(looper);
@@ -1125,7 +1071,6 @@
          * <p><ul>
          *     <li>MSG_PRE_REBOOT_VERIFICATION_START</li>
          *     <li>MSG_PRE_REBOOT_VERIFICATION_APEX</li>
-         *     <li>MSG_PRE_REBOOT_VERIFICATION_APK</li>
          *     <li>MSG_PRE_REBOOT_VERIFICATION_END</li>
          * </ul></p>
          *
@@ -1133,8 +1078,7 @@
          */
         private static final int MSG_PRE_REBOOT_VERIFICATION_START = 1;
         private static final int MSG_PRE_REBOOT_VERIFICATION_APEX = 2;
-        private static final int MSG_PRE_REBOOT_VERIFICATION_APK = 3;
-        private static final int MSG_PRE_REBOOT_VERIFICATION_END = 4;
+        private static final int MSG_PRE_REBOOT_VERIFICATION_END = 3;
 
         @Override
         public void handleMessage(Message msg) {
@@ -1154,9 +1098,6 @@
                     case MSG_PRE_REBOOT_VERIFICATION_APEX:
                         handlePreRebootVerification_Apex(session, rollbackId);
                         break;
-                    case MSG_PRE_REBOOT_VERIFICATION_APK:
-                        handlePreRebootVerification_Apk(session);
-                        break;
                     case MSG_PRE_REBOOT_VERIFICATION_END:
                         handlePreRebootVerification_End(session);
                         break;
@@ -1169,35 +1110,15 @@
             }
         }
 
-        // Notify the handler that system is ready, and reschedule the pre-reboot verifications.
-        private synchronized void readyToStart() {
-            mIsReady = true;
-            if (mPendingSessions != null) {
-                for (int i = 0; i < mPendingSessions.size(); i++) {
-                    StagedSession session = mPendingSessions.get(i);
-                    startPreRebootVerification(session);
-                }
-                mPendingSessions = null;
-            }
-        }
-
         // Method for starting the pre-reboot verification
         private synchronized void startPreRebootVerification(
                 @NonNull StagedSession session) {
-            if (!mIsReady) {
-                if (mPendingSessions == null) {
-                    mPendingSessions = new ArrayList<>();
-                }
-                mPendingSessions.add(session);
-                return;
-            }
-
-            if (session.notifyStartPreRebootVerification()) {
+            mBootCompleted.thenRun(() -> {
                 int sessionId = session.sessionId();
                 Slog.d(TAG, "Starting preRebootVerification for session " + sessionId);
                 obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, -1, session)
                         .sendToTarget();
-            }
+            });
         }
 
         private void onPreRebootVerificationFailure(StagedSession session,
@@ -1226,12 +1147,6 @@
 
         private void notifyPreRebootVerification_Apex_Complete(
                 @NonNull StagedSession session) {
-            obtainMessage(MSG_PRE_REBOOT_VERIFICATION_APK, session.sessionId(), -1, session)
-                    .sendToTarget();
-        }
-
-        private void notifyPreRebootVerification_Apk_Complete(
-                @NonNull StagedSession session) {
             obtainMessage(MSG_PRE_REBOOT_VERIFICATION_END, session.sessionId(), -1, session)
                     .sendToTarget();
         }
@@ -1319,19 +1234,6 @@
         }
 
         /**
-         * Pre-reboot verification state for apk files. Session is sent to
-         * {@link PackageManagerService} for verification and it notifies back the result via
-         * {@link #notifyPreRebootVerification_Apk_Complete}
-         */
-        private void handlePreRebootVerification_Apk(@NonNull StagedSession session) {
-            if (!session.containsApkSession()) {
-                notifyPreRebootVerification_Apk_Complete(session);
-                return;
-            }
-            session.verifySession();
-        }
-
-        /**
          * Pre-reboot verification state for wrapping up:
          * <p><ul>
          *     <li>enables rollback if required</li>
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 878eb92..4e17f9a 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -1,6 +1,22 @@
 {
   "presubmit": [
     {
+      "name": "CtsAtomicInstallTestCases",
+      "file_patterns": [
+        "core/java/.*Install.*",
+        "services/core/.*Install.*",
+        "services/core/java/com/android/server/pm/.*"
+      ]
+    },
+    {
+      "name": "CtsPackageInstallTestCases",
+      "file_patterns": [
+        "core/java/.*Install.*",
+        "services/core/.*Install.*",
+        "services/core/java/com/android/server/pm/.*"
+      ]
+    },
+    {
       "name": "CtsUsesLibraryHostTestCases"
     },
     {
@@ -41,6 +57,53 @@
       ]
     },
     {
+      "name": "FrameworksServicesTests",
+      "file_patterns": ["(/|^)ShortcutService\\.java"],
+      "options": [
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest1"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest2"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest3"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest4"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest5"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest6"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest7"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest8"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest9"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest10"
+        },
+        {
+          "include-filter": "com.android.server.pm.ShortcutManagerTest11"
+        }
+      ]
+    },
+    {
+      "name": "CtsShortcutHostTestCases",
+      "file_patterns": ["(/|^)ShortcutService\\.java"]
+    },
+    {
+      "name": "CtsShortcutManagerTestCases",
+      "file_patterns": ["(/|^)ShortcutService\\.java"]
+    },
+    {
       "name": "CtsContentTestCases",
       "options": [
         {
@@ -79,6 +142,19 @@
       ]
     },
     {
+      "name": "CtsAppSecurityHostTestCases",
+      "file_patterns": [
+        "core/java/.*Install.*",
+        "services/core/.*Install.*",
+        "services/core/java/com/android/server/pm/.*"
+      ],
+      "options": [
+        {
+          "include-filter": "android.appsecurity.cts.SplitTests"
+        }
+      ]
+    },
+    {
       "name": "FrameworksCoreTests",
       "options": [
         {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d4feb3a..89f2bfe 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4814,8 +4814,15 @@
         final int userSerial = userInfo.serialNumber;
         // Migrate only if build fingerprints mismatch
         boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint);
+
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("prepareUserData-" + userId);
         mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
+        t.traceEnd();
+
+        t.traceBegin("reconcileAppsData-" + userId);
         mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE, migrateAppsData);
+        t.traceEnd();
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 471a4d3..0d2bcec 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -21,8 +21,8 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser;
 import android.content.pm.PermissionGroupInfo;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ParsingPackageRead;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.component.ParsedAttribution;
@@ -200,7 +200,7 @@
      * The signature data of all APKs in this package, which must be exactly the same across the
      * base and splits.
      */
-    PackageParser.SigningDetails getSigningDetails();
+    SigningDetails getSigningDetails();
 
     /**
      * TODO(b/135203078): Move split stuff to an inner data class
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 5ee612b..b30c9da 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -196,6 +196,12 @@
             }
         }
 
+        if (pkg.getBackupAgentName() != null) {
+            if (Objects.equals(className, pkg.getBackupAgentName())) {
+                return true;
+            }
+        }
+
         return false;
     }
 
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 7fbe953..2234022 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -22,7 +22,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.ParsingPackageImpl;
 import android.content.pm.parsing.component.ParsedActivity;
@@ -252,7 +252,7 @@
     }
 
     @Override
-    public PackageImpl setSigningDetails(@Nullable PackageParser.SigningDetails value) {
+    public PackageImpl setSigningDetails(@Nullable SigningDetails value) {
         super.setSigningDetails(value);
         return this;
     }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 657f32c..8e4ee6a 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -17,7 +17,7 @@
 package com.android.server.pm.parsing.pkg;
 
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.SigningDetails;
 
 /**
  * Methods used for mutation after direct package parsing, mostly done inside
@@ -59,7 +59,7 @@
 
     ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi);
 
-    ParsedPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+    ParsedPackage setSigningDetails(SigningDetails signingDetails);
 
     ParsedPackage setSplitCodePaths(String[] splitCodePaths);
 
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index cda4806..b1b46af 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -304,10 +304,6 @@
                 & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0;
     }
 
-    public boolean isDocumenter() {
-        return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
-    }
-
     public boolean isConfigurator() {
         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR) != 0;
     }
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 38e9d3e..af63039 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -84,12 +84,13 @@
 import android.content.pm.PackageManager.PermissionInfoFlags;
 import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.component.ParsedPermission;
 import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.permission.CompatibilityPermissionInfo;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
@@ -2827,7 +2828,7 @@
                             // Except...  if this is a permission that was added
                             // to the platform (note: need to only do this when
                             // updating the platform).
-                            if (!isNewPlatformPermissionForPackage(perm, pkg)) {
+                            if (!isCompatPlatformPermissionForPackage(perm, pkg)) {
                                 shouldGrantNormalPermission = false;
                             }
                         }
@@ -3363,14 +3364,12 @@
         return result;
     }
 
-    private static boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
+    private static boolean isCompatPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
         boolean allowed = false;
-        final int NP = PackageParser.NEW_PERMISSIONS.length;
-        for (int ip=0; ip<NP; ip++) {
-            final PackageParser.NewPermissionInfo npi
-                    = PackageParser.NEW_PERMISSIONS[ip];
-            if (npi.name.equals(perm)
-                    && pkg.getTargetSdkVersion() < npi.sdkVersion) {
+        for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) {
+            final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i];
+            if (info.name.equals(perm)
+                    && pkg.getTargetSdkVersion() < info.sdkVersion) {
                 allowed = true;
                 Log.i(TAG, "Auto-granting " + perm + " to old pkg "
                         + pkg.getPackageName());
@@ -3490,15 +3489,15 @@
         //     - or it shares a common signing certificate in its lineage with the defining package,
         //       and the defining package still trusts the old certificate for permissions
         //     - or it shares the above relationships with the system package
-        final PackageParser.SigningDetails sourceSigningDetails =
+        final SigningDetails sourceSigningDetails =
                 getSourcePackageSigningDetails(bp);
         return sourceSigningDetails.hasCommonSignerWithCapability(
                         pkg.getSigningDetails(),
-                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)
+                        SigningDetails.CertCapabilities.PERMISSION)
                 || pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails())
                 || systemPackage.getSigningDetails().checkCapability(
                         pkg.getSigningDetails(),
-                        PackageParser.SigningDetails.CertCapabilities.PERMISSION);
+                        SigningDetails.CertCapabilities.PERMISSION);
     }
 
     private boolean shouldGrantPermissionByProtectionFlags(@NonNull AndroidPackage pkg,
@@ -3608,14 +3607,6 @@
             // Special permissions for the device configurator.
             allowed = true;
         }
-        if (!allowed && bp.isDocumenter()
-                && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
-                        PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM),
-                pkg.getPackageName())) {
-            // If this permission is to be granted to the documenter and
-            // this app is the documenter, then it gets the permission.
-            allowed = true;
-        }
         if (!allowed && bp.isIncidentReportApprover()
                 && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                         PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER,
@@ -3656,11 +3647,11 @@
     }
 
     @NonNull
-    private PackageParser.SigningDetails getSourcePackageSigningDetails(
+    private SigningDetails getSourcePackageSigningDetails(
             @NonNull Permission bp) {
         final PackageSetting ps = getSourcePackageSetting(bp);
         if (ps == null) {
-            return PackageParser.SigningDetails.UNKNOWN;
+            return SigningDetails.UNKNOWN;
         }
         return ps.getSigningDetails();
     }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index adf8f0d..844111a 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -182,10 +182,10 @@
 
         if (!reusedMap.isEmpty()) {
             if (!wasHeaderPrinted) {
-                Signature[] signatures = pkg.getSigningDetails().signatures;
+                Signature[] signatures = pkg.getSigningDetails().getSignatures();
                 String signaturesDigest = signatures == null ? null : Arrays.toString(
                         PackageUtils.computeSignaturesSha256Digests(
-                                pkg.getSigningDetails().signatures, ":"));
+                                pkg.getSigningDetails().getSignatures(), ":"));
 
                 writer.println(pkgState.getPackageName() + ":");
                 writer.increaseIndent();
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index 3c9b106..04b5005 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -16,10 +16,8 @@
 
 package com.android.server.policy;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Rect;
-import android.hardware.ICameraService;
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
 import android.hardware.display.DisplayManagerInternal;
@@ -27,13 +25,11 @@
 import android.os.HandlerExecutor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.IDisplayFoldListener;
 
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
-import com.android.server.camera.CameraServiceProxy;
 import com.android.server.wm.WindowManagerInternal;
 
 /**
@@ -41,13 +37,8 @@
  * TODO(b/126160895): Move DisplayFoldController from PhoneWindowManager to DisplayPolicy.
  */
 class DisplayFoldController {
-    private static final String TAG = "DisplayFoldController";
-
     private final WindowManagerInternal mWindowManagerInternal;
     private final DisplayManagerInternal mDisplayManagerInternal;
-    // Camera service proxy can be disabled through a config.
-    @Nullable
-    private final CameraServiceProxy mCameraServiceProxy;
     private final int mDisplayId;
     private final Handler mHandler;
 
@@ -64,12 +55,10 @@
 
     DisplayFoldController(
             Context context, WindowManagerInternal windowManagerInternal,
-            DisplayManagerInternal displayManagerInternal,
-            @Nullable CameraServiceProxy cameraServiceProxy, int displayId, Rect foldedArea,
+            DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea,
             Handler handler) {
         mWindowManagerInternal = windowManagerInternal;
         mDisplayManagerInternal = displayManagerInternal;
-        mCameraServiceProxy = cameraServiceProxy;
         mDisplayId = displayId;
         mFoldedArea = new Rect(foldedArea);
         mHandler = handler;
@@ -124,16 +113,6 @@
             }
         }
 
-        if (mCameraServiceProxy != null) {
-            if (folded) {
-                mCameraServiceProxy.setDeviceStateFlags(ICameraService.DEVICE_STATE_FOLDED);
-            } else {
-                mCameraServiceProxy.clearDeviceStateFlags(ICameraService.DEVICE_STATE_FOLDED);
-            }
-        } else {
-            Slog.w(TAG, "Camera service unavailable to toggle folded state.");
-        }
-
         mDurationLogger.setDeviceFolded(folded);
         mDurationLogger.logFocusedAppWithFoldState(folded, mFocusedApp);
         mFolded = folded;
@@ -188,8 +167,6 @@
                 LocalServices.getService(WindowManagerInternal.class);
         final DisplayManagerInternal displayService =
                 LocalServices.getService(DisplayManagerInternal.class);
-        final CameraServiceProxy cameraServiceProxy =
-                LocalServices.getService(CameraServiceProxy.class);
 
         final String configFoldedArea = context.getResources().getString(
                 com.android.internal.R.string.config_foldedArea);
@@ -201,6 +178,6 @@
         }
 
         return new DisplayFoldController(context, windowManagerService, displayService,
-                cameraServiceProxy, displayId, foldedArea, DisplayThread.getHandler());
+                displayId, foldedArea, DisplayThread.getHandler());
     }
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 89d5415..ad43514 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -71,6 +71,7 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
+import com.android.server.utils.TimingsTraceAndSlog;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -365,7 +366,11 @@
             return;
         }
 
+
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("Permission_grant_default_permissions-" + userId);
         grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId);
+        t.traceEnd();
 
         final OnInitializedCallback callback;
 
@@ -375,11 +380,15 @@
         }
 
         // Force synchronization as permissions might have changed
+        t.traceBegin("Permission_synchronize_permissions-" + userId);
         synchronizePermissionsAndAppOpsForUser(userId);
+        t.traceEnd();
 
         // Tell observers we are initialized for this user.
         if (callback != null) {
+            t.traceBegin("Permission_onInitialized-" + userId);
             callback.onInitialized(userId);
+            t.traceEnd();
         }
     }
 
@@ -394,6 +403,7 @@
 
     private void grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@UserIdInt int userId) {
         if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPermsIfNeeded(" + userId + ")");
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
 
         final PackageManagerInternal packageManagerInternal =
                 LocalServices.getService(PackageManagerInternal.class);
@@ -426,9 +436,12 @@
                         }
                     });
             try {
+                t.traceBegin("Permission_callback_waiting-" + userId);
                 future.get();
             } catch (InterruptedException | ExecutionException e) {
                 throw new IllegalStateException(e);
+            } finally {
+                t.traceEnd();
             }
 
             permissionControllerManager.updateUserSensitive();
@@ -494,14 +507,19 @@
      */
     private void synchronizePermissionsAndAppOpsForUser(@UserIdInt int userId) {
         if (DEBUG) Slog.i(LOG_TAG, "synchronizePermissionsAndAppOpsForUser(" + userId + ")");
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
 
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
         final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
                 getUserContext(getContext(), UserHandle.of(userId)));
+        t.traceBegin("Permission_synchronize_addPackages-" + userId);
         packageManagerInternal.forEachPackage(
                 (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
+        t.traceEnd();
+        t.traceBegin("Permission_syncPackages-" + userId);
         synchronizer.syncPackages();
+        t.traceEnd();
     }
 
     private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) {
diff --git a/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
index c2596c7..c08faf8 100644
--- a/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
+++ b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java
@@ -323,7 +323,7 @@
                     dataOutputStream.writeUTF(disabledComponents.valueAt(i));
                 }
 
-                for (final Signature signature : pkg.getSigningDetails().signatures) {
+                for (final Signature signature : pkg.getSigningDetails().getSignatures()) {
                     dataOutputStream.write(signature.toByteArray());
                 }
             } catch (IOException e) {
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 9560f59..7bf3478 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -116,10 +116,10 @@
     static final int ROLLBACK_STATE_DELETED = 4;
 
     /**
-     * The session ID for the staged session if this rollback data represents a staged session,
-     * {@code -1} otherwise.
+     * The session ID associate with this rollback. This is the parent session ID in the case of
+     * a multi-package session.
      */
-    private final int mStagedSessionId;
+    private final int mOriginalSessionId;
 
     /**
      * The rollback info for this rollback.
@@ -181,13 +181,6 @@
     private final int[] mPackageSessionIds;
 
     /**
-     * The number of sessions in the install which are notified with success by
-     * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}.
-     * This rollback will be enabled only after all child sessions finished with success.
-     */
-    private int mNumPackageSessionsWithSuccess;
-
-    /**
      * The extension versions supported at the time of rollback creation.
      */
     @NonNull private final SparseIntArray mExtensionVersions;
@@ -203,24 +196,25 @@
      *
      * @param rollbackId the id of the rollback.
      * @param backupDir the directory where the rollback data is stored.
-     * @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
+     * @param originalSessionId the session id associated with this rollback.
+     * @param isStaged true if this is a staged rollback.
      * @param userId the user that performed the install with rollback enabled.
      * @param installerPackageName the installer package name from the original install session.
      * @param packageSessionIds the session ids for all packages in the install.
      * @param extensionVersions the extension versions supported at the time of rollback creation
      */
-    Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
+    Rollback(int rollbackId, File backupDir, int originalSessionId, boolean isStaged, int userId,
             String installerPackageName, int[] packageSessionIds,
             SparseIntArray extensionVersions) {
         this.info = new RollbackInfo(rollbackId,
                 /* packages */ new ArrayList<>(),
-                /* isStaged */ stagedSessionId != -1,
+                /* isStaged */ isStaged,
                 /* causePackages */ new ArrayList<>(),
                 /* committedSessionId */ -1);
         mUserId = userId;
         mInstallerPackageName = installerPackageName;
         mBackupDir = backupDir;
-        mStagedSessionId = stagedSessionId;
+        mOriginalSessionId = originalSessionId;
         mState = ROLLBACK_STATE_ENABLING;
         mTimestamp = Instant.now();
         mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0];
@@ -228,16 +222,10 @@
         mHandler = Looper.myLooper() != null ? new Handler(Looper.myLooper()) : null;
     }
 
-    Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
-             String installerPackageName) {
-        this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null,
-                new SparseIntArray(0));
-    }
-
     /**
      * Constructs a pre-populated Rollback instance.
      */
-    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
+    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int originalSessionId,
             @RollbackState int state, String stateDescription, boolean restoreUserDataInProgress,
             int userId, String installerPackageName, SparseIntArray extensionVersions) {
         this.info = info;
@@ -245,7 +233,7 @@
         mInstallerPackageName = installerPackageName;
         mBackupDir = backupDir;
         mTimestamp = timestamp;
-        mStagedSessionId = stagedSessionId;
+        mOriginalSessionId = originalSessionId;
         mState = state;
         mStateDescription = stateDescription;
         mRestoreUserDataInProgress = restoreUserDataInProgress;
@@ -298,12 +286,11 @@
     }
 
     /**
-     * Returns the session ID for the staged session if this rollback data represents a staged
-     * session, or {@code -1} otherwise.
+     * Returns the session ID associated with this rollback, or {@code -1} if unknown.
      */
     @AnyThread
-    int getStagedSessionId() {
-        return mStagedSessionId;
+    int getOriginalSessionId() {
+        return mOriginalSessionId;
     }
 
     /**
@@ -838,17 +825,6 @@
     }
 
     /**
-     * Called when a child session finished with success.
-     * Returns true when all child sessions are notified with success. This rollback will be
-     * enabled only after all child sessions finished with success.
-     */
-    @WorkerThread
-    boolean notifySessionWithSuccess() {
-        assertInWorkerThread();
-        return ++mNumPackageSessionsWithSuccess == mPackageSessionIds.length;
-    }
-
-    /**
      * Returns true if all packages in this rollback are enabled. We won't enable this rollback
      * until all packages are enabled. Note we don't count apk-in-apex here since they are enabled
      * automatically when the embedding apex is enabled.
@@ -954,9 +930,8 @@
         ipw.println("-state: " + getStateAsString());
         ipw.println("-stateDescription: " + mStateDescription);
         ipw.println("-timestamp: " + getTimestamp());
-        if (getStagedSessionId() != -1) {
-            ipw.println("-stagedSessionId: " + getStagedSessionId());
-        }
+        ipw.println("-isStaged: " + isStaged());
+        ipw.println("-originalSessionId: " + getOriginalSessionId());
         ipw.println("-packages:");
         ipw.increaseIndent();
         for (PackageRollbackInfo pkg : info.getPackages()) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 9e19f57..f7ed000 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -247,11 +247,6 @@
                                 PackageManagerInternal.class);
                         pm.setEnableRollbackCode(token, ret);
                     });
-
-                    // We're handling the ordered broadcast. Abort the
-                    // broadcast because there is no need for it to go to
-                    // anyone else.
-                    abortBroadcast();
                 }
             }
         }, enableRollbackFilter, null, getHandler());
@@ -611,11 +606,11 @@
                 }
 
                 PackageInstaller.SessionInfo session = mContext.getPackageManager()
-                        .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
+                        .getPackageInstaller().getSessionInfo(rollback.getOriginalSessionId());
                 if (session == null || session.isStagedSessionFailed()) {
                     if (rollback.isEnabling()) {
                         iter.remove();
-                        deleteRollback(rollback, "Session " + rollback.getStagedSessionId()
+                        deleteRollback(rollback, "Session " + rollback.getOriginalSessionId()
                                 + " not existed or failed");
                     }
                     continue;
@@ -789,7 +784,13 @@
             newRollback = createNewRollback(parentSession);
         }
 
-        return enableRollbackForPackageSession(newRollback, packageSession);
+        if (enableRollbackForPackageSession(newRollback, packageSession)) {
+            // Persist the rollback if all packages are enabled. We will make the rollback
+            // available once the whole session is installed successfully.
+            return newRollback.allPackagesEnabled() ? completeEnableRollback(newRollback) : true;
+        } else {
+            return false;
+        }
     }
 
     @WorkerThread
@@ -978,43 +979,10 @@
             throw new SecurityException("notifyStagedSession may only be called by the system.");
         }
 
-        // NOTE: We post this runnable on the RollbackManager's binder thread because we'd prefer
-        // to preserve the invariant that all operations that modify state happen there.
         return awaitResult(() -> {
             assertInWorkerThread();
-            PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
-
-            final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
-            if (session == null) {
-                Slog.e(TAG, "No matching install session for: " + sessionId);
-                return -1;
-            }
-
-            Rollback newRollback = createNewRollback(session);
-            if (!session.isMultiPackage()) {
-                if (!enableRollbackForPackageSession(newRollback, session)) {
-                    Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
-                }
-            } else {
-                for (int childSessionId : session.getChildSessionIds()) {
-                    final PackageInstaller.SessionInfo childSession =
-                            installer.getSessionInfo(childSessionId);
-                    if (childSession == null) {
-                        Slog.e(TAG, "No matching child install session for: " + childSessionId);
-                        break;
-                    }
-                    if (!enableRollbackForPackageSession(newRollback, childSession)) {
-                        Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
-                        break;
-                    }
-                }
-            }
-
-            if (!completeEnableRollback(newRollback)) {
-                return -1;
-            } else {
-                return newRollback.info.getRollbackId();
-            }
+            Rollback rollback = getRollbackForSession(sessionId);
+            return rollback != null ? rollback.info.getRollbackId() : -1;
         });
     }
 
@@ -1124,21 +1092,25 @@
                 Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
             }
 
+            Rollback rollback = getRollbackForSession(sessionId);
+            if (rollback == null || !rollback.isEnabling()
+                    || sessionId != rollback.getOriginalSessionId()) {
+                // We only care about the parent session id which will tell us whether the
+                // whole session is successful or not.
+                return;
+            }
             if (success) {
-                Rollback rollback = getRollbackForSession(sessionId);
-                if (rollback != null && !rollback.isStaged() && rollback.isEnabling()
-                        && rollback.notifySessionWithSuccess()
-                        && completeEnableRollback(rollback)) {
+                if (!rollback.isStaged() && completeEnableRollback(rollback)) {
+                    // completeEnableRollback() ensures the rollback is deleted if not all packages
+                    // are enabled. For staged rollbacks, we will make them available in
+                    // onBootCompleted().
                     makeRollbackAvailable(rollback);
                 }
             } else {
-                Rollback rollback = getRollbackForSession(sessionId);
-                if (rollback != null && rollback.isEnabling()) {
-                    Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
-                            + " for failed session id=" + sessionId);
-                    mRollbacks.remove(rollback);
-                    deleteRollback(rollback, "Session " + sessionId + " failed");
-                }
+                Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
+                        + " for failed session id=" + sessionId);
+                mRollbacks.remove(rollback);
+                deleteRollback(rollback, "Session " + sessionId + " failed");
             }
         }
     }
@@ -1307,7 +1279,7 @@
             rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
                     installerPackageName, packageSessionIds, getExtensionVersions());
         } else {
-            rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId,
+            rollback = mRollbackStore.createNonStagedRollback(rollbackId, parentSessionId, userId,
                     installerPackageName, packageSessionIds, getExtensionVersions());
         }
 
@@ -1339,7 +1311,7 @@
         // We expect mRollbacks to be a very small list; linear search should be plenty fast.
         for (int i = 0; i < mRollbacks.size(); ++i) {
             Rollback rollback = mRollbacks.get(i);
-            if (rollback.getStagedSessionId() == sessionId
+            if (rollback.getOriginalSessionId() == sessionId
                     || rollback.containsSessionId(sessionId)) {
                 return rollback;
             }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index fc62f5b..6b783f7 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -209,23 +209,24 @@
      * Creates a new Rollback instance for a non-staged rollback with
      * backupDir assigned.
      */
-    Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName,
-            int[] packageSessionIds, SparseIntArray extensionVersions) {
+    Rollback createNonStagedRollback(int rollbackId, int originalSessionId, int userId,
+            String installerPackageName, int[] packageSessionIds,
+            SparseIntArray extensionVersions) {
         File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
-        return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName,
-                packageSessionIds, extensionVersions);
+        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ false, userId,
+                installerPackageName, packageSessionIds, extensionVersions);
     }
 
     /**
      * Creates a new Rollback instance for a staged rollback with
      * backupDir assigned.
      */
-    Rollback createStagedRollback(int rollbackId, int stagedSessionId, int userId,
+    Rollback createStagedRollback(int rollbackId, int originalSessionId, int userId,
             String installerPackageName, int[] packageSessionIds,
             SparseIntArray extensionVersions) {
         File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
-        return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName,
-                packageSessionIds, extensionVersions);
+        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ true, userId,
+                installerPackageName, packageSessionIds, extensionVersions);
     }
 
     private static boolean isLinkPossible(File oldFile, File newFile) {
@@ -312,7 +313,7 @@
             JSONObject dataJson = new JSONObject();
             dataJson.put("info", rollbackInfoToJson(rollback.info));
             dataJson.put("timestamp", rollback.getTimestamp().toString());
-            dataJson.put("stagedSessionId", rollback.getStagedSessionId());
+            dataJson.put("originalSessionId", rollback.getOriginalSessionId());
             dataJson.put("state", rollback.getStateAsString());
             dataJson.put("stateDescription", rollback.getStateDescription());
             dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress());
@@ -380,7 +381,9 @@
                 rollbackInfoFromJson(dataJson.getJSONObject("info")),
                 backupDir,
                 Instant.parse(dataJson.getString("timestamp")),
-                dataJson.getInt("stagedSessionId"),
+                // Backward compatibility: Historical rollbacks are not erased upon OTA update.
+                //  Need to load the old field 'stagedSessionId' as fallback.
+                dataJson.optInt("originalSessionId", dataJson.optInt("stagedSessionId", -1)),
                 rollbackStateFromString(dataJson.getString("state")),
                 dataJson.optString("stateDescription"),
                 dataJson.getBoolean("restoreUserDataInProgress"),
diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
index a582914..82ba60f 100644
--- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
+++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
@@ -53,17 +53,15 @@
     private static final String TAG = RemoteRotationResolverService.class.getSimpleName();
 
     private final long mIdleUnbindTimeoutMs;
-    private final Object mLock;
 
     RemoteRotationResolverService(Context context, ComponentName serviceName,
-            int userId, long idleUnbindTimeoutMs, Object lock) {
+            int userId, long idleUnbindTimeoutMs) {
         super(context,
                 new Intent(RotationResolverService.SERVICE_INTERFACE).setComponent(serviceName),
                 BIND_FOREGROUND_SERVICE | BIND_INCLUDE_CAPABILITIES, userId,
                 IRotationResolverService.Stub::asInterface);
 
         mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
-        mLock = lock;
 
         // Bind right away.
         connect();
@@ -75,8 +73,7 @@
         return -1;
     }
 
-    @GuardedBy("mLock")
-    public void resolveRotationLocked(RotationRequest request) {
+    public void resolveRotation(RotationRequest request) {
         final RotationResolutionRequest remoteRequest = request.mRemoteRequest;
         post(service -> service.resolveRotation(request.mIRotationResolverCallback, remoteRequest));
 
@@ -97,13 +94,15 @@
         @NonNull
         private final IRotationResolverCallback mIRotationResolverCallback;
         @NonNull
-        private ICancellationSignal mCancellation;
-        @NonNull
         private final CancellationSignal mCancellationSignalInternal;
         @NonNull
         final RotationResolverInternal.RotationResolverCallbackInternal
                 mCallbackInternal;
 
+        @NonNull
+        @GuardedBy("mLock")
+        private ICancellationSignal mCancellation;
+
         @GuardedBy("mLock")
         boolean mIsFulfilled;
 
@@ -111,17 +110,19 @@
         final RotationResolutionRequest mRemoteRequest;
 
         boolean mIsDispatched;
-        private final Object mLock = new Object();
+        private final Object mLock;
         private final long mRequestStartTimeMillis;
 
         RotationRequest(
                 @NonNull RotationResolverInternal.RotationResolverCallbackInternal callbackInternal,
-                RotationResolutionRequest request, @NonNull CancellationSignal cancellationSignal) {
+                RotationResolutionRequest request, @NonNull CancellationSignal cancellationSignal,
+                Object lock) {
             mCallbackInternal = callbackInternal;
             mRemoteRequest = request;
             mIRotationResolverCallback = new RotationResolverCallback(this);
             mCancellationSignalInternal = cancellationSignal;
             mRequestStartTimeMillis = SystemClock.elapsedRealtime();
+            mLock = lock;
         }
 
 
@@ -153,7 +154,7 @@
         }
 
         private static class RotationResolverCallback extends IRotationResolverCallback.Stub {
-            private WeakReference<RotationRequest> mRequestWeakReference;
+            private final WeakReference<RotationRequest> mRequestWeakReference;
 
             RotationResolverCallback(RotationRequest request) {
                 this.mRequestWeakReference = new WeakReference<>(request);
@@ -215,7 +216,6 @@
                         }
                     }
                 }
-
             }
         }
     }
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
index ccf096e..29f3d10 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
@@ -121,26 +121,26 @@
         final RotationResolverInternal.RotationResolverCallbackInternal wrapper =
                 new RotationResolverInternal.RotationResolverCallbackInternal() {
 
-            @Override
-            public void onSuccess(int result) {
-                synchronized (mLock) {
-                    mLatencyTracker
-                            .onActionEnd(ACTION_ROTATE_SCREEN_CAMERA_CHECK);
-                }
-                callbackInternal.onSuccess(result);
-            }
+                    @Override
+                    public void onSuccess(int result) {
+                        synchronized (mLock) {
+                            mLatencyTracker
+                                    .onActionEnd(ACTION_ROTATE_SCREEN_CAMERA_CHECK);
+                        }
+                        callbackInternal.onSuccess(result);
+                    }
 
-            @Override
-            public void onFailure(int error) {
-                synchronized (mLock) {
-                    mLatencyTracker
-                            .onActionEnd(ACTION_ROTATE_SCREEN_CAMERA_CHECK);
-                }
-                callbackInternal.onFailure(error);
-            }
-        };
+                    @Override
+                    public void onFailure(int error) {
+                        synchronized (mLock) {
+                            mLatencyTracker
+                                    .onActionEnd(ACTION_ROTATE_SCREEN_CAMERA_CHECK);
+                        }
+                        callbackInternal.onFailure(error);
+                    }
+                };
         mCurrentRequest = new RemoteRotationResolverService.RotationRequest(wrapper,
-                request, cancellationSignalInternal);
+                request, cancellationSignalInternal, mLock);
 
         cancellationSignalInternal.setOnCancelListener(() -> {
             synchronized (mLock) {
@@ -152,7 +152,7 @@
         });
 
 
-        mRemoteService.resolveRotationLocked(mCurrentRequest);
+        mRemoteService.resolveRotation(mCurrentRequest);
         mCurrentRequest.mIsDispatched = true;
     }
 
@@ -160,7 +160,7 @@
     private void ensureRemoteServiceInitiated() {
         if (mRemoteService == null) {
             mRemoteService = new RemoteRotationResolverService(getContext(), mComponentName,
-                    getUserId(), CONNECTION_TTL_MILLIS, mLock);
+                    getUserId(), CONNECTION_TTL_MILLIS);
         }
     }
 
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index 6366280..e006b65 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -21,24 +21,23 @@
 import android.hardware.audio.common.V2_0.Uuid;
 import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
 import android.hardware.soundtrigger.V2_3.ISoundTriggerHw;
-import android.hardware.soundtrigger.V2_3.Properties;
+import android.media.soundtrigger.AudioCapabilities;
+import android.media.soundtrigger.ConfidenceLevel;
+import android.media.soundtrigger.ModelParameter;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.Phrase;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionMode;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
 import android.media.audio.common.AudioConfig;
 import android.media.audio.common.AudioOffloadInfo;
-import android.media.soundtrigger_middleware.AudioCapabilities;
-import android.media.soundtrigger_middleware.ConfidenceLevel;
-import android.media.soundtrigger_middleware.ModelParameter;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.Phrase;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.RecognitionMode;
-import android.media.soundtrigger_middleware.RecognitionStatus;
-import android.media.soundtrigger_middleware.SoundModel;
-import android.media.soundtrigger_middleware.SoundModelType;
-import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
 import android.os.HidlMemory;
 import android.os.HidlMemoryUtil;
 import android.os.ParcelFileDescriptor;
@@ -55,9 +54,9 @@
  */
 class ConversionUtil {
     static @NonNull
-    SoundTriggerModuleProperties hidl2aidlProperties(
+    Properties hidl2aidlProperties(
             @NonNull ISoundTriggerHw.Properties hidlProperties) {
-        SoundTriggerModuleProperties aidlProperties = new SoundTriggerModuleProperties();
+        Properties aidlProperties = new Properties();
         aidlProperties.implementor = hidlProperties.implementor;
         aidlProperties.description = hidlProperties.description;
         aidlProperties.version = hidlProperties.version;
@@ -75,9 +74,9 @@
         return aidlProperties;
     }
 
-    static @NonNull SoundTriggerModuleProperties hidl2aidlProperties(
-            @NonNull Properties hidlProperties) {
-        SoundTriggerModuleProperties aidlProperties = hidl2aidlProperties(hidlProperties.base);
+    static @NonNull Properties hidl2aidlProperties(
+            @NonNull android.hardware.soundtrigger.V2_3.Properties hidlProperties) {
+        Properties aidlProperties = hidl2aidlProperties(hidlProperties.base);
         aidlProperties.supportedModelArch = hidlProperties.supportedModelArch;
         aidlProperties.audioCapabilities =
                 hidl2aidlAudioCapabilities(hidlProperties.audioCapabilities);
@@ -216,9 +215,11 @@
     }
 
     static @NonNull android.hardware.soundtrigger.V2_3.RecognitionConfig aidl2hidlRecognitionConfig(
-            @NonNull RecognitionConfig aidlConfig) {
+            @NonNull RecognitionConfig aidlConfig, int deviceHandle, int ioHandle) {
         android.hardware.soundtrigger.V2_3.RecognitionConfig hidlConfig =
                 new android.hardware.soundtrigger.V2_3.RecognitionConfig();
+        hidlConfig.base.header.captureDevice = deviceHandle;
+        hidlConfig.base.header.captureHandle = ioHandle;
         hidlConfig.base.header.captureRequested = aidlConfig.captureRequested;
         for (PhraseRecognitionExtra aidlPhraseExtra : aidlConfig.phraseRecognitionExtras) {
             hidlConfig.base.header.phrases.add(aidl2hidlPhraseRecognitionExtra(aidlPhraseExtra));
@@ -299,8 +300,6 @@
         aidlEvent.status = hidl2aidlRecognitionStatus(hidlEvent.status);
         aidlEvent.type = hidl2aidlSoundModelType(hidlEvent.type);
         aidlEvent.captureAvailable = hidlEvent.captureAvailable;
-        // hidlEvent.captureSession is never a valid field.
-        aidlEvent.captureSession = -1;
         aidlEvent.captureDelayMs = hidlEvent.captureDelayMs;
         aidlEvent.capturePreambleMs = hidlEvent.capturePreambleMs;
         aidlEvent.triggerInData = hidlEvent.triggerInData;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java b/services/core/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
new file mode 100644
index 0000000..2f2cb59
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.hardware.soundtrigger.V2_0.ISoundTriggerHw;
+import android.os.HwBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * This is the basic implementation of HalFactory, which uses either the default STHAL or a mock.
+ *
+ * The choice of which HAL to use is as follows:
+ * - Get the (int) value of "debug.soundtrigger_middleware.use_mock_hal" sysprop, if it doesn't
+ *   exist, assume 0.
+ * - If the value is 0, use the default HAL on the device. Connect to the latest-version "default"
+ *   instance declared in the device manifest (either AIDL or HIDL).
+ * - If the value is 2, connect to a "mock" instance of the latest v2.x (HIDL).
+ * - If the value is 3, connect to a "mock" instance of soundtrigger3 (AIDL).
+ * - Otherwise, throw.
+ */
+class DefaultHalFactory implements HalFactory {
+    private static final String TAG = "SoundTriggerMiddlewareDefaultHalFactory";
+
+    private static final @NonNull ICaptureStateNotifier mCaptureStateNotifier =
+            new ExternalCaptureStateTracker();
+
+    private static final int USE_DEFAULT_HAL = 0;
+    private static final int USE_MOCK_HAL_V2 = 2;
+    private static final int USE_MOCK_HAL_V3 = 3;
+
+    @Override
+    public ISoundTriggerHal create() {
+        try {
+            int mockHal = SystemProperties.getInt("debug.soundtrigger_middleware.use_mock_hal",
+                    USE_DEFAULT_HAL);
+            if (mockHal == USE_DEFAULT_HAL) {
+                // Use production HAL.
+
+                // Try soundtrigger3 (AIDL) first.
+                final String aidlServiceName =
+                        android.hardware.soundtrigger3.ISoundTriggerHw.class.getCanonicalName()
+                                + "/default";
+                if (ServiceManager.isDeclared(aidlServiceName)) {
+                    Log.i(TAG, "Connecting to default soundtrigger3.ISoundTriggerHw");
+                    return new SoundTriggerHw3Compat(ServiceManager.waitForService(aidlServiceName),
+                            () -> {
+                                // This property needs to be defined in an init.rc script and
+                                // trigger a HAL reboot.
+                                SystemProperties.set("sys.audio.restart.hal", "1");
+                            });
+                }
+
+                // Fallback to soundtrigger-V2.x (HIDL).
+                Log.i(TAG, "Connecting to default soundtrigger-V2.x.ISoundTriggerHw");
+                ISoundTriggerHw driver = ISoundTriggerHw.getService(true);
+                return SoundTriggerHw2Compat.create(driver, () -> {
+                    // This property needs to be defined in an init.rc script and
+                    // trigger a HAL reboot.
+                    SystemProperties.set("sys.audio.restart.hal", "1");
+                }, mCaptureStateNotifier);
+            } else if (mockHal == USE_MOCK_HAL_V2) {
+                // Use V2 mock.
+                Log.i(TAG, "Connecting to mock soundtrigger-V2.x.ISoundTriggerHw");
+                HwBinder.setTrebleTestingOverride(true);
+                try {
+                    ISoundTriggerHw driver = ISoundTriggerHw.getService("mock", true);
+                    return SoundTriggerHw2Compat.create(driver, () -> {
+                        try {
+                            driver.debug(null, new ArrayList<>(Arrays.asList("reboot")));
+                        } catch (Exception e) {
+                            Log.e(TAG, "Failed to reboot mock HAL", e);
+                        }
+                    }, mCaptureStateNotifier);
+                } finally {
+                    HwBinder.setTrebleTestingOverride(false);
+                }
+            } else if (mockHal == USE_MOCK_HAL_V3) {
+                // Use V3 mock.
+                final String aidlServiceName =
+                        android.hardware.soundtrigger3.ISoundTriggerHw.class.getCanonicalName()
+                                + "/mock";
+                Log.i(TAG, "Connecting to mock soundtrigger3.ISoundTriggerHw");
+                return new SoundTriggerHw3Compat(ServiceManager.waitForService(aidlServiceName),
+                        () -> {
+                            try {
+                                ServiceManager.waitForService(aidlServiceName).shellCommand(null,
+                                        null, null, new String[]{"reboot"}, null, null);
+                            } catch (Exception e) {
+                                Log.e(TAG, "Failed to reboot mock HAL", e);
+                            }
+                        });
+            } else {
+                throw new RuntimeException("Unknown HAL mock version: " + mockHal);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
index 9404904..d195fbe 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
@@ -16,42 +16,55 @@
 
 package com.android.server.soundtrigger_middleware;
 
+import android.annotation.NonNull;
 import android.util.Log;
 
+import java.util.LinkedList;
+import java.util.List;
 import java.util.concurrent.Semaphore;
-import java.util.function.Consumer;
 
 /**
  * This is a never-give-up listener for sound trigger external capture state notifications, as
  * published by the audio policy service.
  *
  * This class will constantly try to connect to the service over a background thread and tolerate
- * its death. The client will be notified by a single provided function that is called in a
- * synchronized manner.
- * For simplicity, there is currently no way to stop the tracker. This is possible to add if the
- * need ever arises.
+ * its death.
  */
-class ExternalCaptureStateTracker {
+class ExternalCaptureStateTracker implements ICaptureStateNotifier {
     private static final String TAG = "CaptureStateTracker";
-    /** Our client's listener. */
-    private final Consumer<Boolean> mListener;
+
+    /** Our client's listeners. Also used as lock. */
+    private final List<Listener> mListeners = new LinkedList<>();
+
+    /** Conservatively, until notified otherwise, we assume capture is active. */
+    private boolean mCaptureActive = true;
+
     /** This semaphore will get a permit every time we need to reconnect. */
     private final Semaphore mNeedToConnect = new Semaphore(1);
 
     /**
      * Constructor. Will start a background thread to do the work.
-     *
-     * @param listener A client provided listener that will be called on state
-     *                 changes. May be
-     *                 called multiple consecutive times with the same value. Never
-     *                 called
-     *                 concurrently.
      */
-    ExternalCaptureStateTracker(Consumer<Boolean> listener) {
-        mListener = listener;
+    ExternalCaptureStateTracker() {
         new Thread(this::run).start();
     }
 
+
+    @Override
+    public boolean registerListener(@NonNull Listener listener) {
+        synchronized (mListeners) {
+            mListeners.add(listener);
+            return mCaptureActive;
+        }
+    }
+
+    @Override
+    public void unregisterListener(Listener listener) {
+        synchronized (mListeners) {
+            mListeners.remove(listener);
+        }
+    }
+
     /**
      * Routine for the background thread. Keeps trying to reconnect.
      */
@@ -74,7 +87,12 @@
      */
     private void setCaptureState(boolean active) {
         try {
-            mListener.accept(active);
+            synchronized (mListeners) {
+                mCaptureActive = active;
+                for (Listener listener : mListeners) {
+                    listener.onCaptureStateChange(active);
+                }
+            }
         } catch (Exception e) {
             Log.e(TAG, "Exception caught while setting capture state", e);
         }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java b/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java
index b19e2ed..6da8a79 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java
@@ -16,16 +16,14 @@
 
 package com.android.server.soundtrigger_middleware;
 
-import android.hardware.soundtrigger.V2_0.ISoundTriggerHw;
-
 /**
- * A factory for creating instances of {@link ISoundTriggerHw}.
+ * A factory for creating instances of {@link ISoundTriggerHal}.
  *
  * @hide
  */
 public interface HalFactory {
     /**
-     * @return An instance of {@link ISoundTriggerHw}.
+     * @return An instance of {@link ISoundTriggerHal}.
      */
-    ISoundTriggerHw create();
+    ISoundTriggerHal create();
 }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java b/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java
new file mode 100644
index 0000000..07d83ca
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+
+/**
+ * Allow registering listeners for tracking changes in audio capture state (when recording starts /
+ * stops). The client will be notified in a synchronized manner.
+ */
+interface ICaptureStateNotifier {
+    interface Listener {
+        void onCaptureStateChange(boolean state);
+    }
+
+    /**
+     * Register a listener for state change notifications. Returns the current capture state and
+     * any subsequent changes will be sent to the listener.
+     * @param listener The listener.
+     * @return The state at the time of registration.
+     */
+    boolean registerListener(@NonNull Listener listener);
+
+    /**
+     * Unregister a listener, previously registered with {@link #registerListener(Listener)}.
+     * Once this call returns, no more invocations of the listener will be made.
+     */
+    void unregisterListener(@NonNull Listener listener);
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
new file mode 100644
index 0000000..aa85dd0
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.hardware.soundtrigger3.ISoundTriggerHw;
+import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
+import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.SoundModel;
+import android.os.IBinder;
+
+/**
+ * This interface mimics the soundtrigger HAL interface, with a few key differences:
+ * <ul>
+ * <li>Generally, methods should not throw, except for the following cases:
+ *   <ul>
+ *   <li>Any unexpected HAL behavior is considered an internal HAL malfunction and should be thrown
+ *   as a {@link HalException}, from any method.
+ *   <li>A {@link RuntimeException} with a {@link android.os.DeadObjectException} cause represents
+ *   a dead HAL process and may be thrown by any method.
+ *   <li>Implementations of earlier versions of the interface may throw a
+ *   {@link RecoverableException} with a
+ *   {@link android.media.soundtrigger.Status#OPERATION_NOT_SUPPORTED} for methods that
+ *   have been introduced in later versions of the interface.
+ *   <li>Certain methods are allowed to throw a {@link RecoverableException} with a
+ *   {@link android.media.soundtrigger.Status#RESOURCE_CONTENTION} to indicate transient
+ *   failures.
+ *   </ul>
+ * <li>Some binder-specific details are hidden.
+ * <li>No RemoteExceptions are specified. Some implementations of this interface may rethrow
+ * RemoteExceptions as RuntimeExceptions, some can guarantee handling them somehow and never throw
+ * them.
+ * </ul>
+ * For cases where the client wants to explicitly handle specific versions of the underlying driver
+ * interface, they may call {@link #interfaceDescriptor()}.
+ * <p>
+ * <b>Note to maintainers</b>: This class must always be kept in sync with the latest version,
+ * so that clients have access to the entire functionality without having to burden themselves with
+ * compatibility, as much as possible.
+ */
+interface ISoundTriggerHal {
+    /**
+     * @see ISoundTriggerHw#getProperties()
+     */
+    Properties getProperties();
+
+    /**
+     * @see ISoundTriggerHw#registerGlobalCallback(ISoundTriggerHwGlobalCallback)
+     */
+    void registerCallback(GlobalCallback callback);
+
+    /**
+     * @see ISoundTriggerHw#loadSoundModel(android.media.soundtrigger.SoundModel,
+     * ISoundTriggerHwCallback)
+     */
+    int loadSoundModel(SoundModel soundModel, ModelCallback callback);
+
+    /**
+     * @see ISoundTriggerHw#loadPhraseSoundModel(android.media.soundtrigger.PhraseSoundModel,
+     * ISoundTriggerHwCallback)
+     */
+    int loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback);
+
+    /**
+     * @see ISoundTriggerHw#unloadSoundModel(int)
+     */
+    void unloadSoundModel(int modelHandle);
+
+    /**
+     * @see ISoundTriggerHw#startRecognition(int, int, int, RecognitionConfig)
+     */
+    void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config);
+
+    /**
+     * @see ISoundTriggerHw#stopRecognition(int)
+     */
+    void stopRecognition(int modelHandle);
+
+    /**
+     * @see ISoundTriggerHw#forceRecognitionEvent(int)
+     */
+    void forceRecognitionEvent(int modelHandle);
+
+    /**
+     * @return null if not supported.
+     * @see ISoundTriggerHw#queryParameter(int, int)
+     */
+    ModelParameterRange queryParameter(int modelHandle, int param);
+
+    /**
+     * @see ISoundTriggerHw#getParameter(int, int)
+     */
+    int getModelParameter(int modelHandle, int param);
+
+    /**
+     * @see ISoundTriggerHw#setParameter(int, int, int)
+     */
+    void setModelParameter(int modelHandle, int param, int value);
+
+    /**
+     * @see IBinder#getInterfaceDescriptor()
+     */
+    String interfaceDescriptor();
+
+    /**
+     * @see IBinder#linkToDeath(IBinder.DeathRecipient, int)
+     */
+    void linkToDeath(IBinder.DeathRecipient recipient);
+
+    /**
+     * @see IBinder#unlinkToDeath(IBinder.DeathRecipient, int)
+     */
+    void unlinkToDeath(IBinder.DeathRecipient recipient);
+
+    /*
+     * This is only useful for testing decorators and doesn't actually do anything with the real
+     * HAL. This method would block until all callbacks that were previously generated have been
+     * invoked. For most decorators, this merely flushes the delegate, but for delegates that may
+     * have additional buffers for callbacks this should flush them.
+     */
+    void flushCallbacks();
+
+    /**
+     * Kill and restart the HAL instance. This is typically a last resort for error recovery and may
+     * result in other related services being killed.
+     */
+    void reboot();
+
+    /**
+     * Called when this interface is guaranteed to no longer be used and can free up any resources
+     * used.
+     */
+    void detach();
+
+    /**
+     * Callback interface for model-related events.
+     */
+    interface ModelCallback {
+        /**
+         * @see ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)
+         */
+        void recognitionCallback(int modelHandle, RecognitionEvent event);
+
+        /**
+         * @see ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)
+         */
+        void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event);
+
+        /**
+         * @see ISoundTriggerHwCallback#modelUnloaded(int)
+         */
+        void modelUnloaded(int modelHandle);
+    }
+
+    /**
+     * Callback interface for global events.
+     */
+    interface GlobalCallback {
+        /**
+         * @see ISoundTriggerHwGlobalCallback#onResourcesAvailable()
+         */
+        void onResourcesAvailable();
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java
deleted file mode 100644
index 8b434bd..0000000
--- a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.soundtrigger_middleware;
-
-import android.hardware.soundtrigger.V2_3.ModelParameterRange;
-import android.hidl.base.V1_0.IBase;
-import android.os.IHwBinder;
-
-/**
- * This interface mimics android.hardware.soundtrigger.V2_x.ISoundTriggerHw and
- * android.hardware.soundtrigger.V2_x.ISoundTriggerHwCallback, with a few key differences:
- * <ul>
- * <li>Methods in the original interface generally have a status return value and potentially a
- * second return value which is the actual return value. This is reflected via a synchronous
- * callback, which is not very pleasant to work with. This interface replaces that pattern with
- * the convention that a HalException is thrown for non-OK status, and then we can use the
- * return value for the actual return value.
- * <li>This interface will always include all the methods from the latest 2.x version (and thus
- * from every 2.x version) interface, with the convention that unsupported methods throw a
- * {@link RecoverableException} with a
- * {@link android.media.soundtrigger_middleware.Status#OPERATION_NOT_SUPPORTED}
- * code.
- * <li>Cases where the original interface had multiple versions of a method representing the exact
- * thing, or there exists a trivial conversion between the new and old version, this interface
- * represents only the latest version, without any _version suffixes.
- * <li>Removes some of the obscure IBinder methods.
- * <li>No RemoteExceptions are specified. Some implementations of this interface may rethrow
- * RemoteExceptions as RuntimeExceptions, some can guarantee handling them somehow and never throw
- * them.
- * <li>soundModelCallback has been removed, since nobody cares about it. Implementations are free
- * to silently discard it.
- * </ul>
- * For cases where the client wants to explicitly handle specific versions of the underlying driver
- * interface, they may call {@link #interfaceDescriptor()}.
- * <p>
- * <b>Note to maintainers</b>: This class must always be kept in sync with the latest 2.x version,
- * so that clients have access to the entire functionality without having to burden themselves with
- * compatibility, as much as possible.
- */
-public interface ISoundTriggerHw2 {
-    /**
-     * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#getPropertiesEx(
-     * android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getPropertiesExCallback)
-     */
-    android.hardware.soundtrigger.V2_3.Properties getProperties();
-
-    /**
-     * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#loadSoundModel_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel,
-     * android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback, int,
-     * android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback)
-     */
-    int loadSoundModel(
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel soundModel,
-            SoundTriggerHw2Compat.Callback callback, int cookie);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#loadPhraseSoundModel_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel,
-     * android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback, int,
-     * android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback)
-     */
-    int loadPhraseSoundModel(
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel soundModel,
-            SoundTriggerHw2Compat.Callback callback, int cookie);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#unloadSoundModel(int)
-     */
-    void unloadSoundModel(int modelHandle);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#stopRecognition(int)
-     */
-    void stopRecognition(int modelHandle);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#stopAllRecognitions()
-     */
-    void stopAllRecognitions();
-
-    /**
-     * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#startRecognition_2_3(int,
-     * android.hardware.soundtrigger.V2_3.RecognitionConfig,
-     * android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback, int)
-     */
-    void startRecognition(int modelHandle,
-            android.hardware.soundtrigger.V2_3.RecognitionConfig config,
-            SoundTriggerHw2Compat.Callback callback, int cookie);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#getModelState(int)
-     */
-    void getModelState(int modelHandle);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#getParameter(int, int,
-     * ISoundTriggerHw.getParameterCallback)
-     */
-    int getModelParameter(int modelHandle, int param);
-
-    /**
-     * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#setParameter(int, int, int)
-     */
-    void setModelParameter(int modelHandle, int param, int value);
-
-    /**
-     * @return null if not supported.
-     * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#queryParameter(int, int,
-     * ISoundTriggerHw.queryParameterCallback)
-     */
-    ModelParameterRange queryParameter(int modelHandle, int param);
-
-    /**
-     * @see IHwBinder#linkToDeath(IHwBinder.DeathRecipient, long)
-     */
-    boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie);
-
-    /**
-     * @see IHwBinder#unlinkToDeath(IHwBinder.DeathRecipient)
-     */
-    boolean unlinkToDeath(IHwBinder.DeathRecipient recipient);
-
-    /**
-     * @see IBase#interfaceDescriptor()
-     */
-    String interfaceDescriptor() throws android.os.RemoteException;
-
-    interface Callback {
-        /**
-         * @see android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback#recognitionCallback_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent,
-         * int)
-         */
-        void recognitionCallback(
-                android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event,
-                int cookie);
-
-        /**
-         * @see android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback#phraseRecognitionCallback_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent,
-         * int)
-         */
-        void phraseRecognitionCallback(
-                android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event,
-                int cookie);
-    }
-}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
index a90053a..60f89da 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
@@ -16,18 +16,18 @@
 
 package com.android.server.soundtrigger_middleware;
 
-import android.media.ICaptureStateListener;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 
 /**
- * This interface unifies methods from ISoundTriggerMiddlewareService and ICaptureStateListener.
+ * This interface closely follows ISoundTriggerMiddlewareService with some subtle changes for
+ * convenience.
  *
  * The ISoundTriggerMiddlewareService have been modified to exclude identity information and the
  * RemoteException signature, both of which are only relevant at the service boundary layer.
  */
-public interface ISoundTriggerMiddlewareInternal extends ICaptureStateListener {
+public interface ISoundTriggerMiddlewareInternal {
     /**
      * Query the available modules and their capabilities.
      */
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/README.md b/services/core/java/com/android/server/soundtrigger_middleware/README.md
index 416548d..016e5c9 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/README.md
+++ b/services/core/java/com/android/server/soundtrigger_middleware/README.md
@@ -1,19 +1,145 @@
 # Sound Trigger Middleware
-TODO: Add component description.
 
-## Notes about thread synchronization
+## Overview
+Sound Trigger Middleware is a system service that exposes sound trigger functionality (low-power
+detection of acoustic events) to applications and higher-level system service.
+
+It has the following roles:
+- Isolating the soundtrigger HAL from potentially untrusted clients.
+- Enforcing correct behavior of the clients.
+- Enforcing correct behavior of the HAL and attempting to recover from failures.
+- Enforcing permissions for using soundtrigger functionality.
+- Serializing access to the HAL.
+- Logging soundtrigger usage in a comprehensive and consistent manner.
+- Generating a dumpsys report including current state and history of operations.
+- Providing a standard interface regardless which version of the HAL is implemented and gracefully
+  degrading operation whenever necessary.
+
+## Structure
+
+The service implementation can be divided into three main layers:
+
+- The "bottom layer" is concerned with HAL compatibility - making all HAL versions look and behave
+  the same.
+- The "middle layer" is concerned with the business logic of the service.
+- The "top layer" is concerned with exposing this functionality as a System Service and integrating
+  with other parts of the system.
+
+### HAL Compatibility Layer
+
+This layer implements the `ISoundTriggerHal` interface, which is the version-agnostic representation
+of the sound trigger HAL driver. It has two main implementations, `SoundTriggerHw2Compat` and
+`SoundTriggerHw3Compat` responsible for adapting to V2.x and V3 HAL drivers, respectively, including
+supporting their respective minor-version differences.
+
+This layer also includes several `ISoundTriggerHal` decorators, such as `SoundTriggerHalWatchdog`
+that enforces deadlines on calls into the HAL, and `SoundTriggerHalEnforcer` which enforces that
+the HAL respects the expected protocol.
+
+The decorator-based design is an effective tool for separation of aspects and modularity, thus
+keeping classes relatively small and focused on one concern. It is also very effective for
+testability by following dependency injection principles.
+
+### Business Logic Layer
+
+This layer also uses a decorator-based design for separation of concerns. The main interface being
+decorated is `ISoundTriggerMiddlwareInternal`, which closely follows the external-facing AIDL
+interface, `ISoundTriggerMiddlewareService`.
+
+Each of the decorators serves a focused purpose: for example, `SoundTriggerMiddlwarePermission`
+deals with enforcing permissions required for the various methods, `SoundTriggerMiddlewareLogging`
+logs all API usage, `SoundTriggerMiddlewareValidation` enforces correct usage of the protocol and
+isolates client errors from internal server errors.
+
+At the bottom of this decorator stack is `SoundTriggerMiddlewareImpl` / `SoundTriggerModule`, which
+are the adapter between `ISoundTriggerHal` and `ISoundTriggerMiddlwareInternal`, introducing the
+notion of having separate client sessions sharing the same HAL.
+
+### Service Layer
+
+This layer ties everything together. It instantiates the actual system service and the decorator
+stack. It also provides concrete connections to the Audio service (for negotiating sessions shared
+between Audio and Sound Trigger and for notifications about audio recording) and to the various HAL
+factories.
+
+This is the only layer that makes strong assumptions about the environment instead of relying on
+abstractions.
+
+## Error Handling and Exception Conventions
+
+We follow conventions for usage of exceptions in the service, in order to correctly and consistently
+distinguish the following cases:
+
+1. The client has done something wrong.
+2. The service implementation has done something wrong.
+3. The HAL has done something wrong.
+4. Nobody has done anything wrong, but runtime conditions prevent an operation from being fulfilled
+  as intended.
+
+The `SoundTriggerMiddlewarePermission` class would reject any calls from unauthorized clients,
+responding with the appropriate exception.
+
+The `SoundTriggerMiddlewareValidation` class does much of this separation. By validating the
+client's data and state, it would throw a relevant `RuntimeException` exception to the client
+without passing the requests down to the lower layers. Once that is done, any exception thrown from
+the underlying implementation can be assumed to be not the client's fault. If caught, they will be
+classified according to the following rule:
+
+- If they are `RecoverableException`s, they represent category #4 above, and will be presented to
+  the client as `ServiceSpecificException`s with the same error code.
+- Otherwise, they are considered an internal error (including HAL malfunction) and will be
+  presented to the client as `ServiceSpecificException(Status.INTERNAL_ERROR)`.
+
+Internally, we would throw `RecoverableException` whenever appropriate. Whenever a HAL malfunctions,
+`SoundTriggerHalEnforcer` is responsible for rebooting it and throwing an exception. A HAL death is
+considered a valid failure mode, and thus result in `RecoverableException(Status.DEAD_OBJECT)`,
+which ends up as a `ServiceSpecificException(Status.DEAD_OBJECT)` on the client side.
+
+## Notes About Thread Synchronization
 This component has some tricky thread synchronization considerations due to its layered design and
 due to the fact that it is involved in both in-bound and out-bound calls from / to
-external components. To avoid potential deadlocks, a strict locking order must be ensured whenever
-nesting locks. The order is:
-- `SoundTriggerMiddlewareValidation` lock.
-- Audio policy service lock. This one is external - it should be assumed to be held whenever we're
-  inside the `ExternalCaptureStateTracker.setCaptureState()` call stack *AND* to be acquired from
-  within our calls into `AudioSessionProvider.acquireSession()`.
-- `SoundTriggerModule` lock.
+external components.
 
-This dictates careful consideration of callbacks going from `SoundTriggerModule` to
-`SoundTriggerMiddlewareValidation` and especially those coming from the `setCaptureState()` path.
-We always invoke those calls outside of the `SoundTriggerModule` lock, so we can lock
-`SoundTriggerMiddlewareValidation`. However, in the `setCaptureState()` case, we have to use atomics
-in `SoundTriggerMiddlewareValidation` and avoid the lock.
+The following mutexes need to be considered:
+- Typically, a one or more mutexes that exist in every layer of the sound trigger middleware stack
+  to serialize access to its internal state or to external components.
+- Audio Policy Service lock. This one is external - it should be assumed to be held whenever we're
+  inside the `ExternalCaptureStateTracker.setCaptureState()` call stack *AND* to be acquired from
+  within our calls into `AudioSessionProvider.acquireSession()` /
+  `AudioSessionProvider.releaseSession()`.
+
+To avoid potential deadlocks, a strict locking order must be ensured whenever nesting locks. The
+order is:
+- Upper layers of the stack, starting from the top (i.e. may not attempt to acquire a higher-layer
+  mutex while a lower-layer mutex is being held) until `ISoundTriggerHw2`.
+- Audio Policy Service lock.
+- Lower layers of the stack, starting from `ISoundTriggerHw2` all the way down to the HAL.
+
+In order to enforce this order, some conventions are established around when it is safe for a module
+to call another module, while having its local mutex(es) held:
+- Most calls (see exceptions below) originating from SoundTriggerMiddlewareService simply propagate
+  down the decorator stack. It is legal to call into the next layer down while holding a local
+  mutex. It is illegal to invoke a callback with a local mutex held.
+- Callbacks propagate from the lower layers up to the upper layers. It is legal to hold a local
+  mutex within a callback, but **not** while call to an upper layer.
+- In order to be able to synchronize, despite the asynchronous nature of callbacks,
+  `stopRecognition()` and `unloadModel()` work differently. They guarantee that once they return,
+  the callbacks associated with them will no longer be called. This implies that they have to block
+  until any pending callbacks are done processing and since these callbacks are potentially holding
+  locks of higher-order mutexes, we must not be holding a local mutex while calling down. The proper
+  sequence for these calls is:
+  - Obtain the local lock if needed. Update/check local state as necessary.
+  - Call the respective method of the delegate ("downwards"). Once it returns, not more callbacks
+    related to this operation will be called.
+  - Obtain the local lock if needed. Update local state as necessary. Assume that state might have
+    changed while the lock has been released.
+  - Release the local lock.
+  - Invoke any synchronous callbacks if needed.
+- Calling from `SoundTriggerMiddlewareImpl` / `SoundTriggerModule` into the audio policy service via
+  `acquireSession()` / `releaseSession()` while holding the local lock is legal.
+- `setCaptureState()` calls, originating from Audio Policy Service, into the lower layers of the
+  stack may call into the HAL (specifically, they must invoke `stopRecognition()`, but must not
+  block on callbacks. For this reason, `SoundTriggerHw2ConcurrentCaptureHandler`, which is the 
+  recipient of these calls, features a buffer and an additional thread, which allows the actual
+  stopping to be synchronous, as required, without having to block the call upon higher layers
+  processing the callbacks.
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
new file mode 100644
index 0000000..e3ce719
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.media.permission.SafeCloseable;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
+import android.media.soundtrigger.Status;
+import android.os.IBinder;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This is a decorator around ISoundTriggerHal, which implements enforcement of concurrent capture
+ * constraints, for HAL implementations older than V2.4 (later versions support this feature at the
+ * HAL level).
+ * <p>
+ * Decorating an instance with this class would result in all active recognitions being aborted as
+ * soon as capture state becomes active. This class ensures consistent handling of abortions coming
+ * from that HAL and abortions coming from concurrent capture, in that only one abort event will be
+ * delivered, irrespective of the relative timing of the two events.
+ * <p>
+ * There are some delicate thread-safety issues handled here:
+ * <ul>
+ * <li>When a model is stopped via stopRecognition(), we guarantee that by the time the call
+ * returns, there will be no more recognition events (including abort) delivered for this model.
+ * This implies synchronous stopping and blocking until all pending events have been delivered.
+ * <li>When a model is stopped via onCaptureStateChange(true), the stopping of the recognition at
+ * the HAL level must be synchronous, but the call must not block on the delivery of the
+ * callbacks, due to the risk of a deadlock: the onCaptureStateChange() calls are typically
+ * invoked with the audio policy mutex held, so must not call method which may attempt to lock
+ * higher-level mutexes. See README.md in this directory for further details.
+ * </ul>
+ * The way this behavior is achieved is by having an additional thread with an event queue, which
+ * joins together model events coming from the delegate module with abort events originating from
+ * this layer (as result of external capture).
+ */
+public class SoundTriggerHalConcurrentCaptureHandler implements ISoundTriggerHal,
+        ICaptureStateNotifier.Listener {
+    private final @NonNull ISoundTriggerHal mDelegate;
+    private GlobalCallback mGlobalCallback;
+
+    /**
+     * Information about a model that is currently loaded. This is needed in order to be able to
+     * send abort events to its designated callback.
+     */
+    private static class LoadedModel {
+        final int type;
+        final @NonNull ModelCallback callback;
+
+        private LoadedModel(int type, @NonNull ModelCallback callback) {
+            this.type = type;
+            this.callback = callback;
+        }
+    }
+
+    /**
+     * This map holds the model type for every model that is loaded.
+     */
+    private final @NonNull Map<Integer, LoadedModel> mLoadedModels = new ConcurrentHashMap<>();
+
+    /**
+     * A set of all models that are currently active.
+     * We use this in order to know which models to stop in case of external capture.
+     * Used as a lock to synchronize operations that effect activity.
+     */
+    private final @NonNull Set<Integer> mActiveModels = new HashSet<>();
+
+    /**
+     * Notifier for changes in capture state.
+     */
+    private final @NonNull ICaptureStateNotifier mNotifier;
+
+    /**
+     * Whether capture is active.
+     */
+    private boolean mCaptureState;
+
+    /**
+     * Since we're wrapping the death recipient, we need to keep a translation map for unlinking.
+     * Key is the client recipient, value is the wrapper.
+     */
+    private final @NonNull Map<IBinder.DeathRecipient, IBinder.DeathRecipient>
+            mDeathRecipientMap = new ConcurrentHashMap<>();
+
+    private final @NonNull CallbackThread mCallbackThread = new CallbackThread();
+
+    public SoundTriggerHalConcurrentCaptureHandler(
+            @NonNull ISoundTriggerHal delegate,
+            @NonNull ICaptureStateNotifier notifier) {
+        mDelegate = delegate;
+        mNotifier = notifier;
+        mCaptureState = mNotifier.registerListener(this);
+    }
+
+    @Override
+    public void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config) {
+        synchronized (mActiveModels) {
+            if (mCaptureState) {
+                throw new RecoverableException(Status.RESOURCE_CONTENTION);
+            }
+            mDelegate.startRecognition(modelHandle, deviceHandle, ioHandle, config);
+            mActiveModels.add(modelHandle);
+        }
+    }
+
+    @Override
+    public void stopRecognition(int modelHandle) {
+        synchronized (mActiveModels) {
+            mDelegate.stopRecognition(modelHandle);
+            mActiveModels.remove(modelHandle);
+        }
+        // Block until all previous events are delivered. Since this is potentially blocking on
+        // upward calls, it must be done outside the lock.
+        mCallbackThread.flush();
+    }
+
+    @Override
+    public void onCaptureStateChange(boolean active) {
+        synchronized (mActiveModels) {
+            if (active) {
+                // Abort all active models. This must be done as one transaction to the event
+                // thread, in order to be able to dedupe events before they are delivered.
+                try (SafeCloseable ignored = mCallbackThread.stallReader()) {
+                    for (int modelHandle : mActiveModels) {
+                        mDelegate.stopRecognition(modelHandle);
+                        LoadedModel model = mLoadedModels.get(modelHandle);
+                        // An abort event must be the last one for its model.
+                        mCallbackThread.pushWithDedupe(modelHandle, true,
+                                () -> notifyAbort(modelHandle, model));
+                    }
+                }
+            } else {
+                mGlobalCallback.onResourcesAvailable();
+            }
+
+            mCaptureState = active;
+        }
+    }
+
+    @Override
+    public int loadSoundModel(SoundModel soundModel, ModelCallback callback) {
+        int handle = mDelegate.loadSoundModel(soundModel, new CallbackWrapper(callback));
+        mLoadedModels.put(handle, new LoadedModel(SoundModelType.GENERIC, callback));
+        return handle;
+    }
+
+    @Override
+    public int loadPhraseSoundModel(PhraseSoundModel soundModel,
+            ModelCallback callback) {
+        int handle = mDelegate.loadPhraseSoundModel(soundModel, new CallbackWrapper(callback));
+        mLoadedModels.put(handle, new LoadedModel(SoundModelType.KEYPHRASE, callback));
+        return handle;
+    }
+
+    @Override
+    public void unloadSoundModel(int modelHandle) {
+        mLoadedModels.remove(modelHandle);
+        mDelegate.unloadSoundModel(modelHandle);
+    }
+
+    @Override
+    public void registerCallback(GlobalCallback callback) {
+        mGlobalCallback = new GlobalCallback() {
+            @Override
+            public void onResourcesAvailable() {
+                mCallbackThread.push(callback::onResourcesAvailable);
+            }
+        };
+        mDelegate.registerCallback(mGlobalCallback);
+    }
+
+    @Override
+    public void linkToDeath(IBinder.DeathRecipient recipient) {
+        IBinder.DeathRecipient wrapper = new IBinder.DeathRecipient() {
+            @Override
+            public void binderDied() {
+                mCallbackThread.push(() -> recipient.binderDied());
+            }
+        };
+        mDelegate.linkToDeath(wrapper);
+        mDeathRecipientMap.put(recipient, wrapper);
+    }
+
+    @Override
+    public void unlinkToDeath(IBinder.DeathRecipient recipient) {
+        mDelegate.unlinkToDeath(mDeathRecipientMap.remove(recipient));
+    }
+
+    private class CallbackWrapper implements ISoundTriggerHal.ModelCallback {
+        private final @NonNull ISoundTriggerHal.ModelCallback mDelegateCallback;
+
+        private CallbackWrapper(@NonNull ModelCallback delegateCallback) {
+            mDelegateCallback = delegateCallback;
+        }
+
+        @Override
+        public void recognitionCallback(int modelHandle, RecognitionEvent event) {
+            // A recognition event must be the last one for its model, unless it is a forced one
+            // (those leave the model active).
+            mCallbackThread.pushWithDedupe(modelHandle,
+                    event.status != RecognitionStatus.FORCED,
+                    () -> mDelegateCallback.recognitionCallback(modelHandle, event));
+        }
+
+        @Override
+        public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event) {
+            // A recognition event must be the last one for its model, unless it is a forced one
+            // (those leave the model active).
+            mCallbackThread.pushWithDedupe(modelHandle,
+                    event.common.status != RecognitionStatus.FORCED,
+                    () -> mDelegateCallback.phraseRecognitionCallback(modelHandle, event));
+        }
+
+        @Override
+        public void modelUnloaded(int modelHandle) {
+            mCallbackThread.push(() -> mDelegateCallback.modelUnloaded(modelHandle));
+        }
+    }
+
+    @Override
+    public void flushCallbacks() {
+        mDelegate.flushCallbacks();
+        mCallbackThread.flush();
+    }
+
+    /**
+     * This is a thread for asynchronous delivery of callback events, having the following features:
+     * <ul>
+     * <li>Events are processed on a separate thread than the thread that pushed them, in the order
+     * they were pushed.
+     * <li>Events can be deduped upon entry to the queue. This is achieved as follows:
+     * <ul>
+     *     <li>Temporarily stall the reader via {@link #stallReader()}.
+     *     <li>Within this scope, push as many events as needed via
+     *     {@link #pushWithDedupe(int, boolean, Runnable)}.
+     *     If an event with the same model handle as the one being pushed is already in the queue
+     *     and has been marked as "lastForModel", the new event will be discarded before entering
+     *     the queue.
+     *     <li>Finally, un-stall the reader by existing the scope.
+     *     <li>Events that do not require deduping can be pushed via {@link #push(Runnable)}.
+     * </ul>
+     * <li>Events can be flushed via {@link #flush()}. This will block until all events pushed prior
+     * to this call have been fully processed.
+     * </ul>
+     */
+    private static class CallbackThread {
+        private static class Entry {
+            final boolean lastForModel;
+            final int modelHandle;
+            final Runnable runnable;
+
+            private Entry(boolean lastForModel, int modelHandle, Runnable runnable) {
+                this.lastForModel = lastForModel;
+                this.modelHandle = modelHandle;
+                this.runnable = runnable;
+            }
+        }
+
+        private boolean mStallReader = false;
+        private final Queue<Entry> mList = new LinkedList<>();
+        private int mPushCount = 0;
+        private int mProcessedCount = 0;
+
+        /**
+         * Ctor. Starts the thread.
+         */
+        CallbackThread() {
+            new Thread(() -> {
+                try {
+                    while (true) {
+                        pop().run();
+                        synchronized (mList) {
+                            mProcessedCount++;
+                            mList.notifyAll();
+                        }
+                    }
+                } catch (InterruptedException e) {
+                    // If interrupted, exit.
+                }
+            }).start();
+        }
+
+        /**
+         * Push a new runnable to the queue, with no deduping.
+         *
+         * @param runnable The runnable to push.
+         */
+        void push(Runnable runnable) {
+            pushEntry(new Entry(false, 0, runnable), false);
+        }
+
+
+        /**
+         * Push a new runnable to the queue, with deduping.
+         * If an entry with the same model handle is already in the queue and was designated as
+         * last for model, this one will be discarded.
+         *
+         * @param modelHandle The model handle, used for deduping purposes.
+         * @param lastForModel If true, this entry will be considered the last one for this model
+         *                     and any subsequence calls for this handle (whether lastForModel or
+         *                     not) will be discarded while this entry is in the queue.
+         * @param runnable    The runnable to push.
+         */
+        void pushWithDedupe(int modelHandle, boolean lastForModel, Runnable runnable) {
+            pushEntry(new Entry(lastForModel, modelHandle, runnable), true);
+        }
+
+        /**
+         * Block until every entry pushed prior to this call has been processed.
+         */
+        void flush() {
+            try {
+                synchronized (mList) {
+                    int pushCount = mPushCount;
+                    while (mProcessedCount != pushCount) {
+                        mList.wait();
+                    }
+                }
+            } catch (InterruptedException ignored) {
+            }
+        }
+
+        /**
+         * Creates a scope (using a try-with-resources block), within which events that are pushed
+         * remain queued and processed. This is useful in order to utilize deduping.
+         */
+        SafeCloseable stallReader() {
+            synchronized (mList) {
+                mStallReader = true;
+                return () -> {
+                    synchronized (mList) {
+                        mStallReader = false;
+                        mList.notifyAll();
+                    }
+                };
+            }
+        }
+
+        private void pushEntry(Entry entry, boolean dedupe) {
+            synchronized (mList) {
+                if (dedupe) {
+                    for (Entry existing : mList) {
+                        if (existing.lastForModel && existing.modelHandle == entry.modelHandle) {
+                            return;
+                        }
+                    }
+                }
+                mList.add(entry);
+                mPushCount++;
+                mList.notifyAll();
+            }
+        }
+
+        private Runnable pop() throws InterruptedException {
+            synchronized (mList) {
+                while (mStallReader || mList.isEmpty()) {
+                    mList.wait();
+                }
+                return mList.remove().runnable;
+            }
+        }
+    }
+
+    /** Notify the client that recognition has been aborted. */
+    private static void notifyAbort(int modelHandle, LoadedModel model) {
+        switch (model.type) {
+            case SoundModelType.GENERIC: {
+                RecognitionEvent event = new RecognitionEvent();
+                event.status = RecognitionStatus.ABORTED;
+                event.type = SoundModelType.GENERIC;
+                model.callback.recognitionCallback(modelHandle, event);
+            }
+            break;
+
+            case SoundModelType.KEYPHRASE: {
+                PhraseRecognitionEvent event = new PhraseRecognitionEvent();
+                event.common.status = RecognitionStatus.ABORTED;
+                event.common.type = SoundModelType.KEYPHRASE;
+                model.callback.phraseRecognitionCallback(modelHandle, event);
+            }
+            break;
+        }
+    }
+
+    @Override
+    public void detach() {
+        mDelegate.detach();
+        mNotifier.unregisterListener(this);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    // All methods below do trivial delegation - no interesting logic.
+    @Override
+    public void reboot() {
+        mDelegate.reboot();
+    }
+
+    @Override
+    public Properties getProperties() {
+        return mDelegate.getProperties();
+    }
+
+    @Override
+    public void forceRecognitionEvent(int modelHandle) {
+        mDelegate.forceRecognitionEvent(modelHandle);
+    }
+
+    @Override
+    public int getModelParameter(int modelHandle, int param) {
+        return mDelegate.getModelParameter(modelHandle, param);
+    }
+
+    @Override
+    public void setModelParameter(int modelHandle, int param, int value) {
+        mDelegate.setModelParameter(modelHandle, param, value);
+    }
+
+    @Override
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
+        return mDelegate.queryParameter(modelHandle, param);
+    }
+
+    @Override
+    public String interfaceDescriptor() {
+        return mDelegate.interfaceDescriptor();
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
new file mode 100644
index 0000000..6870f4f
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Status;
+import android.os.DeadObjectException;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A decorator around a HAL, which adds some checks that the HAL is behaving as expected.
+ * This is not necessarily a strict enforcement for the HAL contract, but a place to add checks for
+ * common HAL malfunctions, to help track them and assist in debugging.
+ *
+ * The class is thread-safe.
+ */
+public class SoundTriggerHalEnforcer implements ISoundTriggerHal {
+    private static final String TAG = "SoundTriggerHalEnforcer";
+
+    /** The state of a model. */
+    private enum ModelState {
+        /** Model is loaded, but inactive. */
+        INACTIVE,
+        /** Model is active. */
+        ACTIVE,
+        /** A request to stop is being made, which may or may not have been processed yet. */
+        PENDING_STOP,
+    }
+
+    private final ISoundTriggerHal mUnderlying;
+    private final Map<Integer, ModelState> mModelStates = new HashMap<>();
+
+    public SoundTriggerHalEnforcer(
+            ISoundTriggerHal underlying) {
+        mUnderlying = underlying;
+    }
+
+    @Override
+    public Properties getProperties() {
+        try {
+            return mUnderlying.getProperties();
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void registerCallback(GlobalCallback callback) {
+        try {
+            mUnderlying.registerCallback(callback);
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public int loadSoundModel(SoundModel soundModel, ModelCallback callback) {
+        try {
+            synchronized (mModelStates) {
+                int handle = mUnderlying.loadSoundModel(soundModel,
+                        new ModelCallbackEnforcer(callback));
+                mModelStates.put(handle, ModelState.INACTIVE);
+                return handle;
+            }
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public int loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback) {
+        try {
+            synchronized (mModelStates) {
+                int handle = mUnderlying.loadPhraseSoundModel(soundModel,
+                        new ModelCallbackEnforcer(callback));
+                mModelStates.put(handle, ModelState.INACTIVE);
+                return handle;
+            }
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void unloadSoundModel(int modelHandle) {
+        try {
+            // This call into the HAL may block on callback processing, thus must be done outside
+            // of the critical section. After this call returns we are guaranteed to no longer be
+            // getting unload events for that model.
+            mUnderlying.unloadSoundModel(modelHandle);
+            synchronized (mModelStates) {
+                // At this point, the model may have already been removed by a HAL callback, but the
+                // remove() method is a no-op in this case, so thus safe.
+                mModelStates.remove(modelHandle);
+            }
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void stopRecognition(int modelHandle) {
+        try {
+            // This call into the HAL may block on callback processing, thus must be done outside
+            // of the critical section. After this call returns we are guaranteed to no longer be
+            // getting stop events for that model.
+            synchronized (mModelStates) {
+                mModelStates.replace(modelHandle, ModelState.PENDING_STOP);
+            }
+            mUnderlying.stopRecognition(modelHandle);
+            synchronized (mModelStates) {
+                // At this point, the model might have been preemptively unloaded, but replace()
+                // do nothing when the entry does not exist, so all good.
+                mModelStates.replace(modelHandle, ModelState.INACTIVE);
+            }
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config) {
+        try {
+            synchronized (mModelStates) {
+                mUnderlying.startRecognition(modelHandle, deviceHandle, ioHandle, config);
+                mModelStates.replace(modelHandle, ModelState.ACTIVE);
+            }
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void forceRecognitionEvent(int modelHandle) {
+        try {
+            mUnderlying.forceRecognitionEvent(modelHandle);
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public int getModelParameter(int modelHandle, int param) {
+        try {
+            return mUnderlying.getModelParameter(modelHandle, param);
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void setModelParameter(int modelHandle, int param, int value) {
+        try {
+            mUnderlying.setModelParameter(modelHandle, param, value);
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
+        try {
+            return mUnderlying.queryParameter(modelHandle, param);
+        } catch (RuntimeException e) {
+            throw handleException(e);
+        }
+    }
+
+    @Override
+    public void linkToDeath(IBinder.DeathRecipient recipient) {
+        mUnderlying.linkToDeath(recipient);
+    }
+
+    @Override
+    public void unlinkToDeath(IBinder.DeathRecipient recipient) {
+        mUnderlying.unlinkToDeath(recipient);
+    }
+
+    @Override
+    public String interfaceDescriptor() {
+        return mUnderlying.interfaceDescriptor();
+    }
+
+    @Override
+    public void flushCallbacks() {
+        mUnderlying.flushCallbacks();
+    }
+
+    private RuntimeException handleException(RuntimeException e) {
+        if (e instanceof RecoverableException) {
+            throw e;
+        }
+        if (e.getCause() instanceof DeadObjectException) {
+            // Server is dead, no need to reboot.
+            Log.e(TAG, "HAL died");
+            throw new RecoverableException(Status.DEAD_OBJECT);
+        }
+        Log.e(TAG, "Exception caught from HAL, rebooting HAL");
+        reboot();
+        throw e;
+    }
+
+    @Override
+    public void reboot() {
+        mUnderlying.reboot();
+    }
+
+    @Override
+    public void detach() {
+        mUnderlying.detach();
+    }
+
+    private class ModelCallbackEnforcer implements ModelCallback {
+        private final ModelCallback mUnderlying;
+
+        private ModelCallbackEnforcer(
+                ModelCallback underlying) {
+            mUnderlying = underlying;
+        }
+
+        @Override
+        public void recognitionCallback(int model, RecognitionEvent event) {
+            int status = event.status;
+
+            synchronized (mModelStates) {
+                ModelState state = mModelStates.get(model);
+                if (state == null || state == ModelState.INACTIVE) {
+                    Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
+                    reboot();
+                    return;
+                }
+                if (status != RecognitionStatus.FORCED) {
+                    mModelStates.replace(model, ModelState.INACTIVE);
+                }
+            }
+            // Always invoke the delegate from outside the critical section.
+            mUnderlying.recognitionCallback(model, event);
+        }
+
+        @Override
+        public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
+            int status = event.common.status;
+            synchronized (mModelStates) {
+                ModelState state = mModelStates.get(model);
+                if (state == null || state == ModelState.INACTIVE) {
+                    Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
+                    reboot();
+                    return;
+                }
+                if (status != RecognitionStatus.FORCED) {
+                    mModelStates.replace(model, ModelState.INACTIVE);
+                }
+            }
+            // Always invoke the delegate from outside the critical section.
+            mUnderlying.phraseRecognitionCallback(model, event);
+        }
+
+        @Override
+        public void modelUnloaded(int modelHandle) {
+            synchronized (mModelStates) {
+                ModelState state = mModelStates.get(modelHandle);
+                if (state == null) {
+                    Log.wtfStack(TAG, "Unexpected unload event for model: " + modelHandle);
+                    reboot();
+                    return;
+                }
+
+                if (state == ModelState.ACTIVE) {
+                    Log.wtfStack(TAG, "Trying to unload an active model: " + modelHandle);
+                    reboot();
+                    return;
+                }
+                mModelStates.remove(modelHandle);
+            }
+            // Always invoke the delegate from outside the critical section.
+            mUnderlying.modelUnloaded(modelHandle);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java
new file mode 100644
index 0000000..7dd28e0
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalMaxModelLimiter.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Status;
+import android.os.IBinder;
+
+/**
+ * This is a decorator around ISoundTriggerHal, which implements enforcement of the maximum number
+ * of models supported by the HAL, for HAL implementations older than V2.4 that do not support
+ * rejection of model loading at the HAL layer.
+ * Since preemptive model unloading has been introduced in V2.4, it should never be used in
+ * conjunction with this class, hence we don't bother considering preemtive unloading when counting
+ * the number of currently loaded models.
+ */
+public class SoundTriggerHalMaxModelLimiter implements ISoundTriggerHal {
+    private final @NonNull ISoundTriggerHal mDelegate;
+    private final int mMaxModels;
+
+    // This counter is used to enforce the maximum number of loaded models.
+    private int mNumLoadedModels = 0;
+
+    private GlobalCallback mGlobalCallback;
+
+    public SoundTriggerHalMaxModelLimiter(
+            ISoundTriggerHal delegate, int maxModels) {
+        mDelegate = delegate;
+        this.mMaxModels = maxModels;
+    }
+
+    @Override
+    public void reboot() {
+        mDelegate.reboot();
+    }
+
+    @Override
+    public void detach() {
+        mDelegate.detach();
+    }
+
+    @Override
+    public Properties getProperties() {
+        return mDelegate.getProperties();
+    }
+
+    @Override
+    public void registerCallback(GlobalCallback callback) {
+        mGlobalCallback = callback;
+        mDelegate.registerCallback(mGlobalCallback);
+    }
+
+    @Override
+    public int loadSoundModel(SoundModel soundModel, ModelCallback callback) {
+        synchronized (this) {
+            if (mNumLoadedModels == mMaxModels) {
+                throw new RecoverableException(Status.RESOURCE_CONTENTION);
+            }
+            int result = mDelegate.loadSoundModel(soundModel, callback);
+            ++mNumLoadedModels;
+            return result;
+        }
+    }
+
+    @Override
+    public int loadPhraseSoundModel(PhraseSoundModel soundModel,
+            ModelCallback callback) {
+        synchronized (this) {
+            if (mNumLoadedModels == mMaxModels) {
+                throw new RecoverableException(Status.RESOURCE_CONTENTION);
+            }
+            int result = mDelegate.loadPhraseSoundModel(soundModel, callback);
+            ++mNumLoadedModels;
+            return result;
+        }
+    }
+
+    @Override
+    public void unloadSoundModel(int modelHandle) {
+        boolean wasAtMaxCapacity;
+        synchronized (this) {
+            wasAtMaxCapacity = mNumLoadedModels-- == mMaxModels;
+        }
+        try {
+            mDelegate.unloadSoundModel(modelHandle);
+        } catch (Exception e) {
+            synchronized (this) {
+                ++mNumLoadedModels;
+            }
+            throw e;
+        }
+        if (wasAtMaxCapacity) {
+            // It is legal to invoke callbacks from within unloadSoundModel().
+            // See README.md for details.
+            mGlobalCallback.onResourcesAvailable();
+        }
+    }
+
+    @Override
+    public void stopRecognition(int modelHandle) {
+        mDelegate.stopRecognition(modelHandle);
+    }
+
+    @Override
+    public void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config) {
+        mDelegate.startRecognition(modelHandle, deviceHandle, ioHandle, config);
+    }
+
+    @Override
+    public void forceRecognitionEvent(int modelHandle) {
+        mDelegate.forceRecognitionEvent(modelHandle);
+    }
+
+    @Override
+    public int getModelParameter(int modelHandle, int param) {
+        return mDelegate.getModelParameter(modelHandle, param);
+    }
+
+    @Override
+    public void setModelParameter(int modelHandle, int param, int value) {
+        mDelegate.setModelParameter(modelHandle, param, value);
+    }
+
+    @Override
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
+        return mDelegate.queryParameter(modelHandle, param);
+    }
+
+    @Override
+    public void linkToDeath(IBinder.DeathRecipient recipient) {
+        mDelegate.linkToDeath(recipient);
+    }
+
+    @Override
+    public void unlinkToDeath(IBinder.DeathRecipient recipient) {
+        mDelegate.unlinkToDeath(recipient);
+    }
+
+    @Override
+    public String interfaceDescriptor() {
+        return mDelegate.interfaceDescriptor();
+    }
+
+    @Override
+    public void flushCallbacks() {
+        mDelegate.flushCallbacks();
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
new file mode 100644
index 0000000..5fe06ee
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundModel;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.Objects;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * An {@link ISoundTriggerHal} decorator that would enforce deadlines on all calls and reboot the
+ * HAL whenever they expire.
+ */
+public class SoundTriggerHalWatchdog implements ISoundTriggerHal {
+    private static final long TIMEOUT_MS = 3000;
+    private static final String TAG = "SoundTriggerHalWatchdog";
+
+    private final @NonNull ISoundTriggerHal mUnderlying;
+    private final @NonNull Timer mTimer;
+
+    public SoundTriggerHalWatchdog(@NonNull ISoundTriggerHal underlying) {
+        mUnderlying = Objects.requireNonNull(underlying);
+        mTimer = new Timer("SoundTriggerHalWatchdog");
+    }
+
+    @Override
+    public Properties getProperties() {
+        try (Watchdog ignore = new Watchdog()) {
+            return mUnderlying.getProperties();
+        }
+    }
+
+    @Override
+    public void registerCallback(GlobalCallback callback) {
+        try (Watchdog ignore = new Watchdog()) {
+            mUnderlying.registerCallback(callback);
+        }
+    }
+
+    @Override
+    public int loadSoundModel(SoundModel soundModel, ModelCallback callback) {
+        try (Watchdog ignore = new Watchdog()) {
+            return mUnderlying.loadSoundModel(soundModel, callback);
+        }
+    }
+
+    @Override
+    public int loadPhraseSoundModel(PhraseSoundModel soundModel,
+            ModelCallback callback) {
+        try (Watchdog ignore = new Watchdog()) {
+            return mUnderlying.loadPhraseSoundModel(soundModel, callback);
+        }
+    }
+
+    @Override
+    public void unloadSoundModel(int modelHandle) {
+        try (Watchdog ignore = new Watchdog()) {
+            mUnderlying.unloadSoundModel(modelHandle);
+        }
+    }
+
+    @Override
+    public void stopRecognition(int modelHandle) {
+        try (Watchdog ignore = new Watchdog()) {
+            mUnderlying.stopRecognition(modelHandle);
+        }
+    }
+
+    @Override
+    public void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config) {
+        try (Watchdog ignore = new Watchdog()) {
+            mUnderlying.startRecognition(modelHandle, deviceHandle, ioHandle, config);
+        }
+    }
+
+    @Override
+    public void forceRecognitionEvent(int modelHandle) {
+        try (Watchdog ignore = new Watchdog()) {
+            mUnderlying.forceRecognitionEvent(modelHandle);
+        }
+    }
+
+    @Override
+    public int getModelParameter(int modelHandle, int param) {
+        try (Watchdog ignore = new Watchdog()) {
+            return mUnderlying.getModelParameter(modelHandle, param);
+        }
+    }
+
+    @Override
+    public void setModelParameter(int modelHandle, int param, int value) {
+        try (Watchdog ignore = new Watchdog()) {
+            mUnderlying.setModelParameter(modelHandle, param, value);
+        }
+    }
+
+    @Override
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
+        try (Watchdog ignore = new Watchdog()) {
+            return mUnderlying.queryParameter(modelHandle, param);
+        }
+    }
+
+    @Override
+    public void linkToDeath(IBinder.DeathRecipient recipient) {
+        mUnderlying.linkToDeath(recipient);
+    }
+
+    @Override
+    public void unlinkToDeath(IBinder.DeathRecipient recipient) {
+        mUnderlying.unlinkToDeath(recipient);
+    }
+
+    @Override
+    public String interfaceDescriptor() {
+        return mUnderlying.interfaceDescriptor();
+    }
+
+    @Override
+    public void flushCallbacks() {
+        mUnderlying.flushCallbacks();
+    }
+
+    @Override
+    public void reboot() {
+        mUnderlying.reboot();
+    }
+
+    @Override
+    public void detach() {
+        mUnderlying.detach();
+    }
+
+    private class Watchdog implements AutoCloseable {
+        private final @NonNull
+        TimerTask mTask;
+        // This exception is used merely for capturing a stack trace at the time of creation.
+        private final @NonNull
+        Exception mException = new Exception();
+
+        Watchdog() {
+            mTask = new TimerTask() {
+                @Override
+                public void run() {
+                    Log.e(TAG, "HAL deadline expired. Rebooting.", mException);
+                    reboot();
+                }
+            };
+            mTimer.schedule(mTask, TIMEOUT_MS);
+        }
+
+        @Override
+        public void close() {
+            mTask.cancel();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index 2f087f4..7a1f775 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -18,60 +18,116 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.media.soundtrigger_middleware.Status;
+import android.hardware.soundtrigger.V2_0.ISoundTriggerHw;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Status;
+import android.os.IBinder;
 import android.os.IHwBinder;
 import android.os.RemoteException;
+import android.system.OsConstants;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
- * An implementation of {@link ISoundTriggerHw2}, on top of any
+ * An implementation of {@link ISoundTriggerHal}, on top of any
  * android.hardware.soundtrigger.V2_x.ISoundTriggerHw implementation. This class hides away some of
  * the details involved with retaining backward compatibility and adapts to the more pleasant syntax
- * exposed by {@link ISoundTriggerHw2}, compared to the bare driver interface.
+ * exposed by {@link ISoundTriggerHal}, compared to the bare driver interface.
  * <p>
  * Exception handling:
  * <ul>
  * <li>All {@link RemoteException}s get rethrown as {@link RuntimeException}.
  * <li>All HAL malfunctions get thrown as {@link HalException}.
  * <li>All unsupported operations get thrown as {@link RecoverableException} with a
- * {@link android.media.soundtrigger_middleware.Status#OPERATION_NOT_SUPPORTED}
+ * {@link android.media.soundtrigger.Status#OPERATION_NOT_SUPPORTED}
  * code.
  * </ul>
  */
-final class SoundTriggerHw2Compat implements ISoundTriggerHw2 {
-    private final @NonNull
-    IHwBinder mBinder;
-    private final @NonNull
-    android.hardware.soundtrigger.V2_0.ISoundTriggerHw mUnderlying_2_0;
-    private final @Nullable
-    android.hardware.soundtrigger.V2_1.ISoundTriggerHw mUnderlying_2_1;
-    private final @Nullable
-    android.hardware.soundtrigger.V2_2.ISoundTriggerHw mUnderlying_2_2;
-    private final @Nullable
-    android.hardware.soundtrigger.V2_3.ISoundTriggerHw mUnderlying_2_3;
+final class SoundTriggerHw2Compat implements ISoundTriggerHal {
+    private final @NonNull Runnable mRebootRunnable;
+    private final @NonNull IHwBinder mBinder;
+    private @NonNull android.hardware.soundtrigger.V2_0.ISoundTriggerHw mUnderlying_2_0;
+    private @Nullable android.hardware.soundtrigger.V2_1.ISoundTriggerHw mUnderlying_2_1;
+    private @Nullable android.hardware.soundtrigger.V2_2.ISoundTriggerHw mUnderlying_2_2;
+    private @Nullable android.hardware.soundtrigger.V2_3.ISoundTriggerHw mUnderlying_2_3;
+    private @Nullable android.hardware.soundtrigger.V2_4.ISoundTriggerHw mUnderlying_2_4;
 
-    public SoundTriggerHw2Compat(
-            @NonNull android.hardware.soundtrigger.V2_0.ISoundTriggerHw underlying) {
-        this(underlying.asBinder());
+    // HAL <=2.1 requires us to pass a callback argument to startRecognition. We will store the one
+    // passed on load and then pass it on start. We don't bother storing the callback on newer
+    // versions.
+    private final @NonNull ConcurrentMap<Integer, ModelCallback> mModelCallbacks =
+            new ConcurrentHashMap<>();
+
+    // A map from IBinder.DeathRecipient to IHwBinder.DeathRecipient for doing the mapping upon
+    // unlinking.
+    private final @NonNull Map<IBinder.DeathRecipient, IHwBinder.DeathRecipient>
+            mDeathRecipientMap = new HashMap<>();
+
+    // The properties are read at construction time and cached, since we need to use some of them
+    // to enforce constraints.
+    private final @NonNull Properties mProperties;
+
+    static ISoundTriggerHal create(
+            @NonNull ISoundTriggerHw underlying,
+            @NonNull Runnable rebootRunnable,
+            ICaptureStateNotifier notifier) {
+        return create(underlying.asBinder(), rebootRunnable, notifier);
     }
 
-    public SoundTriggerHw2Compat(IHwBinder binder) {
-        Objects.requireNonNull(binder);
+    static ISoundTriggerHal create(@NonNull IHwBinder binder,
+            @NonNull Runnable rebootRunnable,
+            ICaptureStateNotifier notifier) {
+        SoundTriggerHw2Compat compat = new SoundTriggerHw2Compat(binder, rebootRunnable);
+        ISoundTriggerHal result = compat;
+        // Add max model limiter for versions <2.4.
+        if (compat.mUnderlying_2_4 == null) {
+            result = new SoundTriggerHalMaxModelLimiter(result,
+                    compat.mProperties.maxSoundModels);
+        }
+        // Add concurrent capture handler for versions <2.4 which do not support concurrent capture.
+        if (compat.mUnderlying_2_4 == null && !compat.mProperties.concurrentCapture) {
+            result = new SoundTriggerHalConcurrentCaptureHandler(result, notifier);
+        }
+        return result;
+    }
 
-        mBinder = binder;
+    private SoundTriggerHw2Compat(@NonNull IHwBinder binder, @NonNull Runnable rebootRunnable) {
+        mRebootRunnable = Objects.requireNonNull(rebootRunnable);
+        mBinder = Objects.requireNonNull(binder);
+        initUnderlying(binder);
+        mProperties = Objects.requireNonNull(getPropertiesInternal());
+    }
 
+    private void initUnderlying(IHwBinder binder) {
         // We want to share the proxy instances rather than create a separate proxy for every
         // version, so we go down the versions in descending order to find the latest one supported,
         // and then simply up-cast it to obtain all the versions that are earlier.
 
+        // Attempt 2.4
+        android.hardware.soundtrigger.V2_4.ISoundTriggerHw as2_4 =
+                android.hardware.soundtrigger.V2_4.ISoundTriggerHw.asInterface(binder);
+        if (as2_4 != null) {
+            mUnderlying_2_0 =
+                    mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = as2_4;
+            return;
+        }
+
         // Attempt 2.3
         android.hardware.soundtrigger.V2_3.ISoundTriggerHw as2_3 =
                 android.hardware.soundtrigger.V2_3.ISoundTriggerHw.asInterface(binder);
         if (as2_3 != null) {
             mUnderlying_2_0 = mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = as2_3;
+            mUnderlying_2_4 = null;
             return;
         }
 
@@ -80,7 +136,7 @@
                 android.hardware.soundtrigger.V2_2.ISoundTriggerHw.asInterface(binder);
         if (as2_2 != null) {
             mUnderlying_2_0 = mUnderlying_2_1 = mUnderlying_2_2 = as2_2;
-            mUnderlying_2_3 = null;
+            mUnderlying_2_3 = mUnderlying_2_4 = null;
             return;
         }
 
@@ -89,7 +145,7 @@
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHw.asInterface(binder);
         if (as2_1 != null) {
             mUnderlying_2_0 = mUnderlying_2_1 = as2_1;
-            mUnderlying_2_2 = mUnderlying_2_3 = null;
+            mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = null;
             return;
         }
 
@@ -98,7 +154,7 @@
                 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.asInterface(binder);
         if (as2_0 != null) {
             mUnderlying_2_0 = as2_0;
-            mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = null;
+            mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = null;
             return;
         }
 
@@ -111,12 +167,32 @@
         }
     }
 
+    private static void handleHalStatusAllowBusy(int status, String methodName) {
+        if (status == -OsConstants.EBUSY) {
+            throw new RecoverableException(Status.RESOURCE_CONTENTION);
+        }
+        handleHalStatus(status, methodName);
+    }
+
     @Override
-    public android.hardware.soundtrigger.V2_3.Properties getProperties() {
+    public void reboot() {
+        mRebootRunnable.run();
+    }
+
+    @Override
+    public void detach() {
+        // No-op.
+    }
+
+    @Override
+    public Properties getProperties() {
+        return mProperties;
+    }
+
+    private Properties getPropertiesInternal() {
         try {
             AtomicInteger retval = new AtomicInteger(-1);
-            AtomicReference<android.hardware.soundtrigger.V2_3.Properties>
-                    properties =
+            AtomicReference<android.hardware.soundtrigger.V2_3.Properties> properties =
                     new AtomicReference<>();
             try {
                 as2_3().getProperties_2_3(
@@ -129,30 +205,57 @@
                 return getProperties_2_0();
             }
             handleHalStatus(retval.get(), "getProperties_2_3");
-            return properties.get();
+            return ConversionUtil.hidl2aidlProperties(properties.get());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     @Override
-    public int loadSoundModel(
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel soundModel,
-            Callback callback, int cookie) {
+    public void registerCallback(GlobalCallback callback) {
+        try {
+            try {
+                as2_4().registerGlobalCallback(new GlobalCallbackWrapper(callback));
+            } catch (NotSupported e) {
+                // In versions < 2.4 the events represented by this callback don't exist, we can
+                // safely ignore this.
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public int loadSoundModel(SoundModel soundModel, ModelCallback callback) {
+        android.hardware.soundtrigger.V2_3.ISoundTriggerHw.SoundModel hidlModel =
+                ConversionUtil.aidl2hidlSoundModel(soundModel);
         try {
             AtomicInteger retval = new AtomicInteger(-1);
             AtomicInteger handle = new AtomicInteger(0);
+
             try {
-                as2_1().loadSoundModel_2_1(soundModel, new SoundTriggerCallback(callback), cookie,
+                as2_4().loadSoundModel_2_4(hidlModel, new ModelCallbackWrapper(callback),
                         (r, h) -> {
                             retval.set(r);
                             handle.set(h);
                         });
+                handleHalStatusAllowBusy(retval.get(), "loadSoundModel_2_4");
             } catch (NotSupported e) {
-                // Fall-back to the 2.0 version:
-                return loadSoundModel_2_0(soundModel, callback, cookie);
+                // Fall-back to the 2.1 version:
+                try {
+                    as2_1().loadSoundModel_2_1(hidlModel, new ModelCallbackWrapper(callback),
+                            0,
+                            (r, h) -> {
+                                retval.set(r);
+                                handle.set(h);
+                            });
+                    handleHalStatus(retval.get(), "loadSoundModel_2_1");
+                    mModelCallbacks.put(handle.get(), callback);
+                } catch (NotSupported ee) {
+                    // Fall-back to the 2.0 version:
+                    return loadSoundModel_2_0(hidlModel, callback);
+                }
             }
-            handleHalStatus(retval.get(), "loadSoundModel_2_1");
             return handle.get();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -160,24 +263,35 @@
     }
 
     @Override
-    public int loadPhraseSoundModel(
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel soundModel,
-            Callback callback, int cookie) {
+    public int loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback) {
+        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel hidlModel =
+                ConversionUtil.aidl2hidlPhraseSoundModel(soundModel);
         try {
             AtomicInteger retval = new AtomicInteger(-1);
             AtomicInteger handle = new AtomicInteger(0);
             try {
-                as2_1().loadPhraseSoundModel_2_1(soundModel, new SoundTriggerCallback(callback),
-                        cookie,
+                as2_4().loadPhraseSoundModel_2_4(hidlModel, new ModelCallbackWrapper(callback),
                         (r, h) -> {
                             retval.set(r);
                             handle.set(h);
                         });
+                handleHalStatusAllowBusy(retval.get(), "loadPhraseSoundModel_2_4");
             } catch (NotSupported e) {
-                // Fall-back to the 2.0 version:
-                return loadPhraseSoundModel_2_0(soundModel, callback, cookie);
+                // Fall-back to the 2.1 version:
+                try {
+                    as2_1().loadPhraseSoundModel_2_1(hidlModel, new ModelCallbackWrapper(callback),
+                            0,
+                            (r, h) -> {
+                                retval.set(r);
+                                handle.set(h);
+                            });
+                    handleHalStatus(retval.get(), "loadPhraseSoundModel_2_1");
+                    mModelCallbacks.put(handle.get(), callback);
+                } catch (NotSupported ee) {
+                    // Fall-back to the 2.0 version:
+                    return loadPhraseSoundModel_2_0(hidlModel, callback);
+                }
             }
-            handleHalStatus(retval.get(), "loadSoundModel_2_1");
             return handle.get();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -187,6 +301,8 @@
     @Override
     public void unloadSoundModel(int modelHandle) {
         try {
+            // Safe if key doesn't exist.
+            mModelCallbacks.remove(modelHandle);
             int retval = as2_0().unloadSoundModel(modelHandle);
             handleHalStatus(retval, "unloadSoundModel");
         } catch (RemoteException e) {
@@ -206,26 +322,23 @@
     }
 
     @Override
-    public void stopAllRecognitions() {
-        try {
-            int retval = as2_0().stopAllRecognitions();
-            handleHalStatus(retval, "stopAllRecognitions");
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    @Override
-    public void startRecognition(int modelHandle,
-            android.hardware.soundtrigger.V2_3.RecognitionConfig config,
-            Callback callback, int cookie) {
+    public void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config) {
+        android.hardware.soundtrigger.V2_3.RecognitionConfig hidlConfig =
+                ConversionUtil.aidl2hidlRecognitionConfig(config, deviceHandle, ioHandle);
         try {
             try {
-                int retval = as2_3().startRecognition_2_3(modelHandle, config);
-                handleHalStatus(retval, "startRecognition_2_3");
+                int retval = as2_4().startRecognition_2_4(modelHandle, hidlConfig);
+                handleHalStatusAllowBusy(retval, "startRecognition_2_4");
             } catch (NotSupported e) {
-                // Fall-back to the 2.0 version:
-                startRecognition_2_1(modelHandle, config, callback, cookie);
+                // Fall-back to the 2.3 version:
+                try {
+                    int retval = as2_3().startRecognition_2_3(modelHandle, hidlConfig);
+                    handleHalStatus(retval, "startRecognition_2_3");
+                } catch (NotSupported ee) {
+                    // Fall-back to the 2.0 version:
+                    startRecognition_2_1(modelHandle, hidlConfig);
+                }
             }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -233,7 +346,7 @@
     }
 
     @Override
-    public void getModelState(int modelHandle) {
+    public void forceRecognitionEvent(int modelHandle) {
         try {
             int retval = as2_2().getModelState(modelHandle);
             handleHalStatus(retval, "getModelState");
@@ -276,8 +389,7 @@
     }
 
     @Override
-    public android.hardware.soundtrigger.V2_3.ModelParameterRange queryParameter(int modelHandle,
-            int param) {
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
         AtomicInteger status = new AtomicInteger(-1);
         AtomicReference<android.hardware.soundtrigger.V2_3.OptionalModelParameterRange>
                 optionalRange =
@@ -298,25 +410,36 @@
         return (optionalRange.get().getDiscriminator()
                 == android.hardware.soundtrigger.V2_3.OptionalModelParameterRange.hidl_discriminator.range)
                 ?
-                optionalRange.get().range() : null;
+                ConversionUtil.hidl2aidlModelParameterRange(optionalRange.get().range()) : null;
     }
 
     @Override
-    public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) {
-        return mBinder.linkToDeath(recipient, cookie);
+    public void linkToDeath(IBinder.DeathRecipient recipient) {
+        IHwBinder.DeathRecipient wrapper = cookie -> recipient.binderDied();
+        mDeathRecipientMap.put(recipient, wrapper);
+        mBinder.linkToDeath(wrapper, 0);
     }
 
     @Override
-    public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) {
-        return mBinder.unlinkToDeath(recipient);
+    public void unlinkToDeath(IBinder.DeathRecipient recipient) {
+        mBinder.unlinkToDeath(mDeathRecipientMap.remove(recipient));
     }
 
     @Override
-    public String interfaceDescriptor() throws RemoteException {
-        return as2_0().interfaceDescriptor();
+    public String interfaceDescriptor() {
+        try {
+            return as2_0().interfaceDescriptor();
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
     }
 
-    private android.hardware.soundtrigger.V2_3.Properties getProperties_2_0()
+    @Override
+    public void flushCallbacks() {
+        // This is a no-op. Only implemented for decorators.
+    }
+
+    private Properties getProperties_2_0()
             throws RemoteException {
         AtomicInteger retval = new AtomicInteger(-1);
         AtomicReference<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties>
@@ -328,12 +451,13 @@
                     properties.set(p);
                 });
         handleHalStatus(retval.get(), "getProperties");
-        return Hw2CompatUtil.convertProperties_2_0_to_2_3(properties.get());
+        return ConversionUtil.hidl2aidlProperties(
+                Hw2CompatUtil.convertProperties_2_0_to_2_3(properties.get()));
     }
 
     private int loadSoundModel_2_0(
             android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel soundModel,
-            Callback callback, int cookie)
+            ModelCallback callback)
             throws RemoteException {
         // Convert the soundModel to V2.0.
         android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model_2_0 =
@@ -341,17 +465,18 @@
 
         AtomicInteger retval = new AtomicInteger(-1);
         AtomicInteger handle = new AtomicInteger(0);
-        as2_0().loadSoundModel(model_2_0, new SoundTriggerCallback(callback), cookie, (r, h) -> {
+        as2_0().loadSoundModel(model_2_0, new ModelCallbackWrapper(callback), 0, (r, h) -> {
             retval.set(r);
             handle.set(h);
         });
         handleHalStatus(retval.get(), "loadSoundModel");
+        mModelCallbacks.put(handle.get(), callback);
         return handle.get();
     }
 
     private int loadPhraseSoundModel_2_0(
             android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel soundModel,
-            Callback callback, int cookie)
+            ModelCallback callback)
             throws RemoteException {
         // Convert the soundModel to V2.0.
         android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel model_2_0 =
@@ -359,28 +484,28 @@
 
         AtomicInteger retval = new AtomicInteger(-1);
         AtomicInteger handle = new AtomicInteger(0);
-        as2_0().loadPhraseSoundModel(model_2_0, new SoundTriggerCallback(callback), cookie,
+        as2_0().loadPhraseSoundModel(model_2_0, new ModelCallbackWrapper(callback), 0,
                 (r, h) -> {
                     retval.set(r);
                     handle.set(h);
                 });
         handleHalStatus(retval.get(), "loadSoundModel");
+        mModelCallbacks.put(handle.get(), callback);
         return handle.get();
     }
 
     private void startRecognition_2_1(int modelHandle,
-            android.hardware.soundtrigger.V2_3.RecognitionConfig config,
-            Callback callback, int cookie) {
+            android.hardware.soundtrigger.V2_3.RecognitionConfig config) {
         try {
             try {
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig config_2_1 =
                         Hw2CompatUtil.convertRecognitionConfig_2_3_to_2_1(config);
                 int retval = as2_1().startRecognition_2_1(modelHandle, config_2_1,
-                        new SoundTriggerCallback(callback), cookie);
+                        new ModelCallbackWrapper(mModelCallbacks.get(modelHandle)), 0);
                 handleHalStatus(retval, "startRecognition_2_1");
             } catch (NotSupported e) {
                 // Fall-back to the 2.0 version:
-                startRecognition_2_0(modelHandle, config, callback, cookie);
+                startRecognition_2_0(modelHandle, config);
             }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -388,13 +513,12 @@
     }
 
     private void startRecognition_2_0(int modelHandle,
-            android.hardware.soundtrigger.V2_3.RecognitionConfig config,
-            Callback callback, int cookie)
+            android.hardware.soundtrigger.V2_3.RecognitionConfig config)
             throws RemoteException {
         android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig config_2_0 =
                 Hw2CompatUtil.convertRecognitionConfig_2_3_to_2_0(config);
         int retval = as2_0().startRecognition(modelHandle, config_2_0,
-                new SoundTriggerCallback(callback), cookie);
+                new ModelCallbackWrapper(mModelCallbacks.get(modelHandle)), 0);
         handleHalStatus(retval, "startRecognition");
     }
 
@@ -427,6 +551,14 @@
         return mUnderlying_2_3;
     }
 
+    private @NonNull
+    android.hardware.soundtrigger.V2_4.ISoundTriggerHw as2_4() throws NotSupported {
+        if (mUnderlying_2_4 == null) {
+            throw new NotSupported("Underlying driver version < 2.4");
+        }
+        return mUnderlying_2_4;
+    }
+
     /**
      * A checked exception representing the requested interface version not being supported.
      * At the public interface layer, use {@link #throwAsRecoverableException()} to propagate it to
@@ -448,28 +580,48 @@
         }
     }
 
-    private static class SoundTriggerCallback extends
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.Stub {
-        private final @NonNull
-        Callback mDelegate;
+    private static class GlobalCallbackWrapper extends
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback.Stub {
+        private final @NonNull GlobalCallback mDelegate;
 
-        private SoundTriggerCallback(
-                @NonNull Callback delegate) {
+        private GlobalCallbackWrapper(@NonNull GlobalCallback delegate) {
+            mDelegate = delegate;
+        }
+
+        @Override
+        public void onResourcesAvailable() {
+            mDelegate.onResourcesAvailable();
+        }
+    }
+
+    private static class ModelCallbackWrapper extends
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.Stub {
+        private final @NonNull ModelCallback mDelegate;
+
+        private ModelCallbackWrapper(
+                @NonNull ModelCallback delegate) {
             mDelegate = Objects.requireNonNull(delegate);
         }
 
         @Override
+        public void modelUnloaded(int modelHandle) {
+            mDelegate.modelUnloaded(modelHandle);
+        }
+
+        @Override
         public void recognitionCallback_2_1(
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event,
                 int cookie) {
-            mDelegate.recognitionCallback(event, cookie);
+            mDelegate.recognitionCallback(event.header.model,
+                    ConversionUtil.hidl2aidlRecognitionEvent(event));
         }
 
         @Override
         public void phraseRecognitionCallback_2_1(
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event,
                 int cookie) {
-            mDelegate.phraseRecognitionCallback(event, cookie);
+            mDelegate.phraseRecognitionCallback(event.common.header.model,
+                    ConversionUtil.hidl2aidlPhraseRecognitionEvent(event));
         }
 
         @Override
@@ -485,7 +637,7 @@
                 int cookie) {
             android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event_2_1 =
                     Hw2CompatUtil.convertRecognitionEvent_2_0_to_2_1(event);
-            mDelegate.recognitionCallback(event_2_1, cookie);
+            recognitionCallback_2_1(event_2_1, cookie);
         }
 
         @Override
@@ -494,7 +646,7 @@
                 int cookie) {
             android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent
                     event_2_1 = Hw2CompatUtil.convertPhraseRecognitionEvent_2_0_to_2_1(event);
-            mDelegate.phraseRecognitionCallback(event_2_1, cookie);
+            phraseRecognitionCallback_2_1(event_2_1, cookie);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
deleted file mode 100644
index cf7460b..0000000
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.soundtrigger_middleware;
-
-import android.hardware.soundtrigger.V2_1.ISoundTriggerHw;
-import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
-import android.hardware.soundtrigger.V2_3.ModelParameterRange;
-import android.hardware.soundtrigger.V2_3.Properties;
-import android.hardware.soundtrigger.V2_3.RecognitionConfig;
-import android.media.soundtrigger_middleware.Status;
-import android.os.DeadObjectException;
-import android.os.IHwBinder;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A decorator around a HAL, which adds some checks that the HAL is behaving as expected.
- * This is not necessarily a strict enforcement for the HAL contract, but a place to add checks for
- * common HAL malfunctions, to help track them and assist in debugging.
- *
- * The class is thread-safe.
- */
-public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 {
-    static final String TAG = "SoundTriggerHw2Enforcer";
-
-    final ISoundTriggerHw2 mUnderlying;
-    Map<Integer, Boolean> mModelStates = new HashMap<>();
-
-    public SoundTriggerHw2Enforcer(
-            ISoundTriggerHw2 underlying) {
-        mUnderlying = underlying;
-    }
-
-    @Override
-    public Properties getProperties() {
-        try {
-            return mUnderlying.getProperties();
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback,
-            int cookie) {
-        try {
-            int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback),
-                    cookie);
-            synchronized (mModelStates) {
-                mModelStates.put(handle, false);
-            }
-            return handle;
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback,
-            int cookie) {
-        try {
-            int handle = mUnderlying.loadPhraseSoundModel(soundModel,
-                    new CallbackEnforcer(callback),
-                    cookie);
-            synchronized (mModelStates) {
-                mModelStates.put(handle, false);
-            }
-            return handle;
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public void unloadSoundModel(int modelHandle) {
-        try {
-            mUnderlying.unloadSoundModel(modelHandle);
-            synchronized (mModelStates) {
-                mModelStates.remove(modelHandle);
-            }
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public void stopRecognition(int modelHandle) {
-        try {
-            mUnderlying.stopRecognition(modelHandle);
-            synchronized (mModelStates) {
-                mModelStates.replace(modelHandle, false);
-            }
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public void stopAllRecognitions() {
-        try {
-            mUnderlying.stopAllRecognitions();
-            synchronized (mModelStates) {
-                for (Map.Entry<Integer, Boolean> entry : mModelStates.entrySet()) {
-                    entry.setValue(false);
-                }
-            }
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback,
-            int cookie) {
-        // It is possible that an event will be sent before the HAL returns from the
-        // startRecognition call, thus it is important to set the state to active before the call.
-        synchronized (mModelStates) {
-            mModelStates.replace(modelHandle, true);
-        }
-        try {
-            mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback),
-                    cookie);
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public void getModelState(int modelHandle) {
-        try {
-            mUnderlying.getModelState(modelHandle);
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public int getModelParameter(int modelHandle, int param) {
-        try {
-            return mUnderlying.getModelParameter(modelHandle, param);
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public void setModelParameter(int modelHandle, int param, int value) {
-        try {
-            mUnderlying.setModelParameter(modelHandle, param, value);
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public ModelParameterRange queryParameter(int modelHandle, int param) {
-        try {
-            return mUnderlying.queryParameter(modelHandle, param);
-        } catch (RuntimeException e) {
-            throw handleException(e);
-        }
-    }
-
-    @Override
-    public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) {
-        return mUnderlying.linkToDeath(recipient, cookie);
-    }
-
-    @Override
-    public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) {
-        return mUnderlying.unlinkToDeath(recipient);
-    }
-
-    @Override
-    public String interfaceDescriptor() throws RemoteException {
-        return mUnderlying.interfaceDescriptor();
-    }
-
-    private static RuntimeException handleException(RuntimeException e) {
-        if (e.getCause() instanceof DeadObjectException) {
-            // Server is dead, no need to reboot.
-            Log.e(TAG, "HAL died");
-            throw new RecoverableException(Status.DEAD_OBJECT);
-        }
-        Log.e(TAG, "Exception caught from HAL, rebooting HAL");
-        rebootHal();
-        throw e;
-    }
-
-    private static void rebootHal() {
-        // This property needs to be defined in an init.rc script and trigger a HAL reboot.
-        SystemProperties.set("sys.audio.restart.hal", "1");
-    }
-
-    private class CallbackEnforcer implements Callback {
-        private final Callback mUnderlying;
-
-        private CallbackEnforcer(
-                Callback underlying) {
-            mUnderlying = underlying;
-        }
-
-        @Override
-        public void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event,
-                int cookie) {
-            int model = event.header.model;
-            synchronized (mModelStates) {
-                if (!mModelStates.getOrDefault(model, false)) {
-                    Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
-                    rebootHal();
-                    return;
-                }
-                if (event.header.status
-                        != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
-                    mModelStates.replace(model, false);
-                }
-            }
-            mUnderlying.recognitionCallback(event, cookie);
-        }
-
-        @Override
-        public void phraseRecognitionCallback(ISoundTriggerHwCallback.PhraseRecognitionEvent event,
-                int cookie) {
-            int model = event.common.header.model;
-            synchronized (mModelStates) {
-                if (!mModelStates.getOrDefault(model, false)) {
-                    Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
-                    rebootHal();
-                    return;
-                }
-                if (event.common.header.status
-                        != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
-                    mModelStates.replace(model, false);
-                }
-            }
-            mUnderlying.phraseRecognitionCallback(event, cookie);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
deleted file mode 100644
index 212f81f..0000000
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.soundtrigger_middleware;
-
-import android.annotation.NonNull;
-import android.hardware.soundtrigger.V2_1.ISoundTriggerHw;
-import android.hardware.soundtrigger.V2_3.ModelParameterRange;
-import android.hardware.soundtrigger.V2_3.Properties;
-import android.hardware.soundtrigger.V2_3.RecognitionConfig;
-import android.os.IHwBinder;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.util.Log;
-
-import java.util.Objects;
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * An {@link ISoundTriggerHw2} decorator that would enforce deadlines on all calls and reboot the
- * HAL whenever they expire.
- */
-public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
-    private static final long TIMEOUT_MS = 3000;
-    private static final String TAG = "SoundTriggerHw2Watchdog";
-
-    private final @NonNull
-    ISoundTriggerHw2 mUnderlying;
-    private final @NonNull
-    Timer mTimer;
-
-    public SoundTriggerHw2Watchdog(@NonNull ISoundTriggerHw2 underlying) {
-        mUnderlying = Objects.requireNonNull(underlying);
-        mTimer = new Timer("SoundTriggerHw2Watchdog");
-    }
-
-    @Override
-    public Properties getProperties() {
-        try (Watchdog ignore = new Watchdog()) {
-            return mUnderlying.getProperties();
-        }
-    }
-
-    @Override
-    public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback,
-            int cookie) {
-        try (Watchdog ignore = new Watchdog()) {
-            return mUnderlying.loadSoundModel(soundModel, callback, cookie);
-        }
-    }
-
-    @Override
-    public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback,
-            int cookie) {
-        try (Watchdog ignore = new Watchdog()) {
-            return mUnderlying.loadPhraseSoundModel(soundModel, callback, cookie);
-        }
-    }
-
-    @Override
-    public void unloadSoundModel(int modelHandle) {
-        try (Watchdog ignore = new Watchdog()) {
-            mUnderlying.unloadSoundModel(modelHandle);
-        }
-    }
-
-    @Override
-    public void stopRecognition(int modelHandle) {
-        try (Watchdog ignore = new Watchdog()) {
-            mUnderlying.stopRecognition(modelHandle);
-        }
-    }
-
-    @Override
-    public void stopAllRecognitions() {
-        try (Watchdog ignore = new Watchdog()) {
-            mUnderlying.stopAllRecognitions();
-        }
-    }
-
-    @Override
-    public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback,
-            int cookie) {
-        try (Watchdog ignore = new Watchdog()) {
-            mUnderlying.startRecognition(modelHandle, config, callback, cookie);
-        }
-    }
-
-    @Override
-    public void getModelState(int modelHandle) {
-        try (Watchdog ignore = new Watchdog()) {
-            mUnderlying.getModelState(modelHandle);
-        }
-    }
-
-    @Override
-    public int getModelParameter(int modelHandle, int param) {
-        try (Watchdog ignore = new Watchdog()) {
-            return mUnderlying.getModelParameter(modelHandle, param);
-        }
-    }
-
-    @Override
-    public void setModelParameter(int modelHandle, int param, int value) {
-        try (Watchdog ignore = new Watchdog()) {
-            mUnderlying.setModelParameter(modelHandle, param, value);
-        }
-    }
-
-    @Override
-    public ModelParameterRange queryParameter(int modelHandle, int param) {
-        try (Watchdog ignore = new Watchdog()) {
-            return mUnderlying.queryParameter(modelHandle, param);
-        }
-    }
-
-    @Override
-    public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) {
-        return mUnderlying.linkToDeath(recipient, cookie);
-    }
-
-    @Override
-    public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) {
-        return mUnderlying.unlinkToDeath(recipient);
-    }
-
-    @Override
-    public String interfaceDescriptor() throws RemoteException {
-        return mUnderlying.interfaceDescriptor();
-    }
-
-    private static void rebootHal() {
-        // This property needs to be defined in an init.rc script and trigger a HAL reboot.
-        SystemProperties.set("sys.audio.restart.hal", "1");
-    }
-
-    private class Watchdog implements AutoCloseable {
-        private final @NonNull
-        TimerTask mTask;
-        // This exception is used merely for capturing a stack trace at the time of creation.
-        private final @NonNull
-        Exception mException = new Exception();
-
-        Watchdog() {
-            mTask = new TimerTask() {
-                @Override
-                public void run() {
-                    Log.e(TAG, "HAL deadline expired. Rebooting.", mException);
-                    rebootHal();
-                }
-            };
-            mTimer.schedule(mTask, TIMEOUT_MS);
-        }
-
-        @Override
-        public void close() {
-            mTask.cancel();
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
new file mode 100644
index 0000000..f564756
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.hardware.soundtrigger3.ISoundTriggerHw;
+import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
+import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Status;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+public class SoundTriggerHw3Compat implements ISoundTriggerHal {
+    private final @NonNull ISoundTriggerHw mDriver;
+    private final @NonNull Runnable mRebootRunnable;
+
+    public SoundTriggerHw3Compat(@NonNull IBinder binder, @NonNull Runnable rebootRunnable) {
+        mDriver = android.hardware.soundtrigger3.ISoundTriggerHw.Stub.asInterface(binder);
+        mRebootRunnable = rebootRunnable;
+    }
+
+    @Override
+    public Properties getProperties() {
+        try {
+            return mDriver.getProperties();
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void registerCallback(GlobalCallback callback) {
+        try {
+            mDriver.registerGlobalCallback(new GlobalCallbackAdaper(callback));
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public int loadSoundModel(SoundModel soundModel, ModelCallback callback) {
+        try {
+            return mDriver.loadSoundModel(soundModel, new ModelCallbackAdaper(callback));
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == Status.RESOURCE_CONTENTION) {
+                throw new RecoverableException(Status.RESOURCE_CONTENTION);
+            }
+            throw e;
+        }
+    }
+
+    @Override
+    public int loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback) {
+        try {
+            return mDriver.loadPhraseSoundModel(soundModel, new ModelCallbackAdaper(callback));
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == Status.RESOURCE_CONTENTION) {
+                throw new RecoverableException(Status.RESOURCE_CONTENTION);
+            }
+            throw e;
+        }
+    }
+
+    @Override
+    public void unloadSoundModel(int modelHandle) {
+        try {
+            mDriver.unloadSoundModel(modelHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void startRecognition(int modelHandle, int deviceHandle, int ioHandle,
+            RecognitionConfig config) {
+        try {
+            mDriver.startRecognition(modelHandle, deviceHandle, ioHandle, config);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == Status.RESOURCE_CONTENTION) {
+                throw new RecoverableException(Status.RESOURCE_CONTENTION);
+            }
+            throw e;
+        }
+    }
+
+    @Override
+    public void stopRecognition(int modelHandle) {
+        try {
+            mDriver.stopRecognition(modelHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void forceRecognitionEvent(int modelHandle) {
+        try {
+            mDriver.forceRecognitionEvent(modelHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public ModelParameterRange queryParameter(int modelHandle, int param) {
+        try {
+            return mDriver.queryParameter(modelHandle, param);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public int getModelParameter(int modelHandle, int param) {
+        try {
+            return mDriver.getParameter(modelHandle, param);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void setModelParameter(int modelHandle, int param, int value) {
+        try {
+            mDriver.setParameter(modelHandle, param, value);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public String interfaceDescriptor() {
+        try {
+            return mDriver.asBinder().getInterfaceDescriptor();
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void linkToDeath(IBinder.DeathRecipient recipient) {
+        try {
+            mDriver.asBinder().linkToDeath(recipient, 0);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void unlinkToDeath(IBinder.DeathRecipient recipient) {
+        mDriver.asBinder().unlinkToDeath(recipient, 0);
+    }
+
+    @Override
+    public void flushCallbacks() {
+        // No-op.
+    }
+
+    @Override
+    public void reboot() {
+        mRebootRunnable.run();
+    }
+
+    @Override
+    public void detach() {
+        // No-op.
+    }
+
+    private static class GlobalCallbackAdaper extends ISoundTriggerHwGlobalCallback.Stub {
+        private final @NonNull GlobalCallback mDelegate;
+
+        public GlobalCallbackAdaper(@NonNull GlobalCallback callback) {
+            mDelegate = callback;
+        }
+
+        @Override
+        public void onResourcesAvailable() {
+            mDelegate.onResourcesAvailable();
+        }
+    }
+
+    private static class ModelCallbackAdaper extends ISoundTriggerHwCallback.Stub {
+        private final @NonNull ModelCallback mDelegate;
+
+        public ModelCallbackAdaper(ModelCallback callback) {
+            mDelegate = callback;
+        }
+
+        @Override
+        public void modelUnloaded(int model) {
+            mDelegate.modelUnloaded(model);
+        }
+
+        @Override
+        public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
+            mDelegate.phraseRecognitionCallback(model, event);
+        }
+
+        @Override
+        public void recognitionCallback(int model, RecognitionEvent event) {
+            mDelegate.recognitionCallback(model, event);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
index d76b1bf..c8c0f3d 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
@@ -17,12 +17,9 @@
 package com.android.server.soundtrigger_middleware;
 
 import android.annotation.NonNull;
-import android.hardware.soundtrigger.V2_0.ISoundTriggerHw;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
-import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.os.IBinder;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -39,7 +36,7 @@
  * <li>There is no binder instance associated with this implementation. Do not call asBinder().
  * <li>The implementation may throw a {@link RecoverableException} to indicate non-fatal,
  * recoverable faults. The error code would one of the
- * {@link android.media.soundtrigger_middleware.Status}
+ * {@link android.media.soundtrigger.Status}
  * constants. Any other exception thrown should be regarded as a bug in the implementation or one
  * of its dependencies (assuming correct usage).
  * <li>The implementation is designed for testibility by featuring dependency injection (the
@@ -84,15 +81,15 @@
             @NonNull AudioSessionProvider audioSessionProvider) {
         List<SoundTriggerModule> modules = new ArrayList<>(halFactories.length);
 
-        for (int i = 0; i < halFactories.length; ++i) {
+        for (HalFactory halFactory : halFactories) {
             try {
-                modules.add(new SoundTriggerModule(halFactories[i], audioSessionProvider));
+                modules.add(new SoundTriggerModule(halFactory, audioSessionProvider));
             } catch (Exception e) {
                 Log.e(TAG, "Failed to add a SoundTriggerModule instance", e);
             }
         }
 
-        mModules = modules.toArray(new SoundTriggerModule[modules.size()]);
+        mModules = modules.toArray(new SoundTriggerModule[0]);
     }
 
     /**
@@ -122,18 +119,4 @@
     ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback) {
         return mModules[handle].attach(callback);
     }
-
-    @Override
-    public void setCaptureState(boolean active) {
-        for (SoundTriggerModule module : mModules) {
-            module.setExternalCaptureState(active);
-        }
-    }
-
-    @Override
-    public @NonNull
-    IBinder asBinder() {
-        throw new UnsupportedOperationException(
-                "This implementation is not inteded to be used directly with Binder.");
-    }
-}
\ No newline at end of file
+}
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 2ef0759..559e777 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -18,16 +18,16 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+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.ModelParameterRange;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -57,9 +57,10 @@
  *     }
  * }
  * </code></pre>
- * The actual handling of these events is then done inside of {@link #logReturnWithObject(Object,
- * String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link
- * #logExceptionWithObject(Object, String, Exception, Object[])}.
+ * The actual handling of these events is then done inside of
+ * {@link #logReturnWithObject(Object, Identity, String, Object, Object[])},
+ * {@link #logVoidReturnWithObject(Object, Identity, String, Object[])} and {@link
+ * #logExceptionWithObject(Object, Identity, String, Exception, Object[])}.
  */
 public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable {
     private static final String TAG = "SoundTriggerMiddlewareLogging";
@@ -96,23 +97,6 @@
         }
     }
 
-    @Override
-    public void setCaptureState(boolean active) throws RemoteException {
-        try {
-            mDelegate.setCaptureState(active);
-            logVoidReturn("setCaptureState", active);
-        } catch (Exception e) {
-            logException("setCaptureState", e, active);
-            throw e;
-        }
-    }
-
-    @Override
-    public IBinder asBinder() {
-        throw new UnsupportedOperationException(
-                "This implementation is not inteded to be used directly with Binder.");
-    }
-
     // Override toString() in order to have the delegate's ID in it.
     @Override
     public String toString() {
@@ -298,10 +282,10 @@
             }
 
             @Override
-            public void onRecognition(int modelHandle, RecognitionEvent event)
+            public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
                     throws RemoteException {
                 try {
-                    mCallbackDelegate.onRecognition(modelHandle, event);
+                    mCallbackDelegate.onRecognition(modelHandle, event, captureSession);
                     logVoidReturn("onRecognition", modelHandle, event);
                 } catch (Exception e) {
                     logException("onRecognition", e, modelHandle, event);
@@ -310,10 +294,11 @@
             }
 
             @Override
-            public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event)
+            public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
+                    int captureSession)
                     throws RemoteException {
                 try {
-                    mCallbackDelegate.onPhraseRecognition(modelHandle, event);
+                    mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
                     logVoidReturn("onPhraseRecognition", modelHandle, event);
                 } catch (Exception e) {
                     logException("onPhraseRecognition", e, modelHandle, event);
@@ -322,12 +307,23 @@
             }
 
             @Override
-            public void onRecognitionAvailabilityChange(boolean available) throws RemoteException {
+            public void onModelUnloaded(int modelHandle) throws RemoteException {
                 try {
-                    mCallbackDelegate.onRecognitionAvailabilityChange(available);
-                    logVoidReturn("onRecognitionAvailabilityChange", available);
+                    mCallbackDelegate.onModelUnloaded(modelHandle);
+                    logVoidReturn("onModelUnloaded", modelHandle);
                 } catch (Exception e) {
-                    logException("onRecognitionAvailabilityChange", e, available);
+                    logException("onModelUnloaded", e, modelHandle);
+                    throw e;
+                }
+            }
+
+            @Override
+            public void onResourcesAvailable() throws RemoteException {
+                try {
+                    mCallbackDelegate.onResourcesAvailable();
+                    logVoidReturn("onResourcesAvailable");
+                } catch (Exception e) {
+                    logException("onResourcesAvailable", e);
                     throw e;
                 }
             }
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 c1f8240..32ba852 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -24,20 +24,20 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.PermissionChecker;
+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.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;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.media.soundtrigger_middleware.Status;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -90,24 +90,12 @@
         return wrapper.attach(mDelegate.attach(handle, wrapper.getCallbackWrapper()));
     }
 
-    @Override
-    public void setCaptureState(boolean active) throws RemoteException {
-        // This is an internal call. No permissions needed.
-        mDelegate.setCaptureState(active);
-    }
-
     // Override toString() in order to have the delegate's ID in it.
     @Override
     public String toString() {
         return Objects.toString(mDelegate);
     }
 
-    @Override
-    public IBinder asBinder() {
-        throw new UnsupportedOperationException(
-                "This implementation is not inteded to be used directly with Binder.");
-    }
-
     /**
      * Get the identity context, or throws an InternalServerError if it has not been established.
      *
@@ -313,22 +301,28 @@
             }
 
             @Override
-            public void onRecognition(int modelHandle, RecognitionEvent event)
+            public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
                     throws RemoteException {
                 enforcePermissions("Sound trigger recognition.");
-                mDelegate.onRecognition(modelHandle, event);
+                mDelegate.onRecognition(modelHandle, event, captureSession);
             }
 
             @Override
-            public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event)
+            public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
+                    int captureSession)
                     throws RemoteException {
                 enforcePermissions("Sound trigger phrase recognition.");
-                mDelegate.onPhraseRecognition(modelHandle, event);
+                mDelegate.onPhraseRecognition(modelHandle, event, captureSession);
             }
 
             @Override
-            public void onRecognitionAvailabilityChange(boolean available) throws RemoteException {
-                mDelegate.onRecognitionAvailabilityChange(available);
+            public void onResourcesAvailable() throws RemoteException {
+                mDelegate.onResourcesAvailable();
+            }
+
+            @Override
+            public void onModelUnloaded(int modelHandle) throws RemoteException {
+                mDelegate.onModelUnloaded(modelHandle);
             }
 
             @Override
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
index db7a575..1995e54 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
@@ -20,7 +20,10 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
-import android.hardware.soundtrigger.V2_0.ISoundTriggerHw;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundModel;
 import android.media.permission.ClearCallingIdentityContext;
 import android.media.permission.Identity;
 import android.media.permission.PermissionUtil;
@@ -28,13 +31,8 @@
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.RemoteException;
-import android.util.Log;
 
 import com.android.server.SystemService;
 
@@ -79,13 +77,6 @@
             @NonNull Context context) {
         mDelegate = Objects.requireNonNull(delegate);
         mContext = context;
-        new ExternalCaptureStateTracker(active -> {
-            try {
-                mDelegate.setCaptureState(active);
-            } catch (RemoteException e) {
-                throw e.rethrowAsRuntimeException();
-            }
-        });
     }
 
     @Override
@@ -232,23 +223,15 @@
 
         @Override
         public void onStart() {
-            HalFactory[] factories = new HalFactory[]{() -> {
-                try {
-                    Log.d(TAG, "Connecting to default ISoundTriggerHw");
-                    return ISoundTriggerHw.getService(true);
-                } catch (RemoteException e) {
-                    throw e.rethrowAsRuntimeException();
-                }
-            }};
+            HalFactory[] factories = new HalFactory[]{new DefaultHalFactory()};
 
             publishBinderService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE,
-                    new SoundTriggerMiddlewareService(
-                            new SoundTriggerMiddlewareLogging(
-                                    new SoundTriggerMiddlewarePermission(
-                                            new SoundTriggerMiddlewareValidation(
-                                                    new SoundTriggerMiddlewareImpl(factories,
-                                                            new AudioSessionProviderImpl())),
-                                            getContext())), getContext()));
+                    new SoundTriggerMiddlewareService(new SoundTriggerMiddlewareLogging(
+                            new SoundTriggerMiddlewarePermission(
+                                    new SoundTriggerMiddlewareValidation(
+                                            new SoundTriggerMiddlewareImpl(factories,
+                                                    new AudioSessionProviderImpl())),
+                                    getContext())), getContext()));
         }
     }
 }
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 95a30c7..d9fa792 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -18,21 +18,21 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+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;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.RecognitionStatus;
-import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
-import android.media.soundtrigger_middleware.Status;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -46,10 +46,6 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * This is a decorator of an {@link ISoundTriggerMiddlewareService}, which enforces correct usage by
@@ -89,7 +85,8 @@
  * }
  * </pre></code>
  * Following this patterns ensures a consistent and rigorous handling of all aspects associated
- * with client-server separation.
+ * with client-server separation. Notable exceptions are stopRecognition() and unloadModel(), which
+ * follow slightly more complicated rules for synchronization (see README.md for details).
  * <p>
  * <b>Exception handling approach:</b><br>
  * We make sure all client faults (argument and state validation) happen first, and
@@ -115,21 +112,18 @@
     }
 
     private class ModuleState {
-        final @NonNull SoundTriggerModuleProperties properties;
-        Set<Session> sessions = new HashSet<>();
+        public @NonNull Properties properties;
+        public Set<Session> sessions = new HashSet<>();
 
-        private ModuleState(@NonNull SoundTriggerModuleProperties properties) {
+        private ModuleState(@NonNull Properties properties) {
             this.properties = properties;
         }
     }
 
-    private AtomicReference<Boolean> mCaptureState = new AtomicReference<>();
-
     private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
     private Map<Integer, ModuleState> mModules;
 
-    public SoundTriggerMiddlewareValidation(
-            @NonNull ISoundTriggerMiddlewareInternal delegate) {
+    public SoundTriggerMiddlewareValidation(@NonNull ISoundTriggerMiddlewareInternal delegate) {
         mDelegate = delegate;
     }
 
@@ -137,8 +131,8 @@
      * Generic exception handling for exceptions thrown by the underlying implementation.
      *
      * Would throw any {@link RecoverableException} as a {@link ServiceSpecificException} (passed
-     * by Binder to the caller) and <i>any other</i> exception as {@link InternalServerError}
-     * (<b>not</b> passed by Binder to the caller).
+     * by Binder to the caller) and <i>any other</i> exception as a {@link ServiceSpecificException}
+     * with a {@link Status#INTERNAL_ERROR} code.
      * <p>
      * Typical usage:
      * <code><pre>
@@ -149,8 +143,7 @@
      * }
      * </pre></code>
      */
-    static @NonNull
-    RuntimeException handleException(@NonNull Exception e) {
+    static @NonNull RuntimeException handleException(@NonNull Exception e) {
         if (e instanceof RecoverableException) {
             throw new ServiceSpecificException(((RecoverableException) e).errorCode,
                     e.getMessage());
@@ -161,8 +154,7 @@
     }
 
     @Override
-    public @NonNull
-    SoundTriggerModuleDescriptor[] listModules() {
+    public @NonNull SoundTriggerModuleDescriptor[] listModules() {
         // Input validation (always valid).
 
         synchronized (this) {
@@ -186,6 +178,7 @@
                             throw new RuntimeException(
                                     "listModules must always return the same result.");
                         }
+                        mModules.get(desc.handle).properties = desc.properties;
                     }
                 }
                 return result;
@@ -223,23 +216,6 @@
         }
     }
 
-    @Override
-    public void setCaptureState(boolean active) {
-        // This is an internal call. No permissions needed.
-        //
-        // Normally, we would acquire a lock here. However, we do not access any state here so it
-        // is safe to not lock. This call is typically done from a different context than all the
-        // other calls and may result in a deadlock if we lock here (between the audio server and
-        // the system server).
-        try {
-            mDelegate.setCaptureState(active);
-        } catch (Exception e) {
-            throw handleException(e);
-        } finally {
-            mCaptureState.set(active);
-        }
-    }
-
     // Override toString() in order to have the delegate's ID in it.
     @Override
     public String toString() {
@@ -247,17 +223,8 @@
     }
 
     @Override
-    public IBinder asBinder() {
-        throw new UnsupportedOperationException(
-                "This implementation is not inteded to be used directly with Binder.");
-    }
-
-    @Override
     public void dump(PrintWriter pw) {
         synchronized (this) {
-            Boolean captureState = mCaptureState.get();
-            pw.printf("Capture state is %s\n\n", captureState == null ? "uninitialized"
-                    : (captureState ? "active" : "inactive"));
             if (mModules != null) {
                 for (int handle : mModules.keySet()) {
                     final ModuleState module = mModules.get(handle);
@@ -303,10 +270,14 @@
              * delivered to the caller (most commonly, for permission reasons).
              */
             INTERCEPTED,
+            /**
+             * Model has been preemptively unloaded by the HAL.
+             */
+            PREEMPTED,
         }
 
         /** Activity state. */
-        private AtomicInteger mActivityState = new AtomicInteger(Activity.LOADED.ordinal());
+        Activity activityState = Activity.LOADED;
 
         /** Human-readable description of the model. */
         final String description;
@@ -316,7 +287,7 @@
          * parameter is supported. A null value means it is known to not be supported. A non-null
          * value indicates the valid value range.
          */
-        private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>();
+        private final Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>();
 
         /**
          * Check that the given parameter is known to be supported for this model.
@@ -351,24 +322,6 @@
             Preconditions.checkArgumentInRange(value, range.minInclusive, range.maxInclusive,
                     "value");
         }
-
-        /**
-         * Update support state for the given parameter for this model.
-         *
-         * @param modelParam The parameter key.
-         * @param range      The parameter value range, or null if not supported.
-         */
-        void updateParameterSupport(int modelParam, @Nullable ModelParameterRange range) {
-            parameterSupport.put(modelParam, range);
-        }
-
-        Activity getActivityState() {
-            return Activity.values()[mActivityState.get()];
-        }
-
-        void setActivityState(Activity activity) {
-            mActivityState.set(activity.ordinal());
-        }
     }
 
     /**
@@ -377,13 +330,7 @@
      */
     private class Session extends ISoundTriggerModule.Stub {
         private ISoundTriggerModule mDelegate;
-        // While generally all the fields of this class must be changed under a lock, an exception
-        // is made for the specific case of changing a model state from ACTIVE to LOADED, which
-        // may happen as result of a recognition callback. This would happen atomically and is
-        // necessary in order to avoid deadlocks associated with locking from within callbacks
-        // possibly originating from the audio server.
-        private @NonNull
-        ConcurrentMap<Integer, ModelState> mLoadedModels = new ConcurrentHashMap<>();
+        private final @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>();
         private final int mHandle;
         private ModuleStatus mState = ModuleStatus.ALIVE;
         private final CallbackWrapper mCallbackWrapper;
@@ -451,7 +398,6 @@
         @Override
         public void unloadModel(int modelHandle) {
             // Input validation (always valid).
-
             synchronized (SoundTriggerMiddlewareValidation.this) {
                 // State validation.
                 if (mState == ModuleStatus.DETACHED) {
@@ -462,18 +408,24 @@
                 if (modelState == null) {
                     throw new IllegalStateException("Invalid handle: " + modelHandle);
                 }
-                if (modelState.getActivityState() != ModelState.Activity.LOADED) {
+                // To avoid race conditions, we treat LOADED and PREEMPTED exactly the same.
+                if (modelState.activityState != ModelState.Activity.LOADED
+                        && modelState.activityState != ModelState.Activity.PREEMPTED) {
                     throw new IllegalStateException("Model with handle: " + modelHandle
                             + " has invalid state for unloading");
                 }
+            }
 
-                // From here on, every exception isn't client's fault.
-                try {
-                    mDelegate.unloadModel(modelHandle);
-                    mLoadedModels.remove(modelHandle);
-                } catch (Exception e) {
-                    throw handleException(e);
-                }
+            // From here on, every exception isn't client's fault.
+            try {
+                // Calling the delegate must be done outside the lock.
+                mDelegate.unloadModel(modelHandle);
+            } catch (Exception e) {
+                throw handleException(e);
+            }
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                mLoadedModels.remove(modelHandle);
             }
         }
 
@@ -492,20 +444,19 @@
                 if (modelState == null) {
                     throw new IllegalStateException("Invalid handle: " + modelHandle);
                 }
-                if (modelState.getActivityState() != ModelState.Activity.LOADED) {
+                ModelState.Activity activityState = modelState.activityState;
+                // To avoid race conditions, we treat LOADED and PREEMPTED exactly the same.
+                if (activityState != ModelState.Activity.LOADED
+                        && activityState != ModelState.Activity.PREEMPTED) {
                     throw new IllegalStateException("Model with handle: " + modelHandle
                             + " has invalid state for starting recognition");
                 }
 
                 // From here on, every exception isn't client's fault.
                 try {
-                    // Normally, we would set the state after the operation succeeds. However, since
-                    // the activity state may be reset outside of the lock, we set it here first,
-                    // and reset it in case of exception.
-                    modelState.setActivityState(ModelState.Activity.ACTIVE);
                     mDelegate.startRecognition(modelHandle, config);
+                    modelState.activityState = ModelState.Activity.ACTIVE;
                 } catch (Exception e) {
-                    modelState.setActivityState(ModelState.Activity.LOADED);
                     throw handleException(e);
                 }
             }
@@ -529,17 +480,36 @@
 
                 // From here on, every exception isn't client's fault.
                 try {
-                    // If the activity state is LOADED or INTERCEPTED, we skip delegating the
-                    // command, but still consider the call valid. In either case, the resulting
-                    // state is LOADED.
-                    if (modelState.getActivityState() == ModelState.Activity.ACTIVE) {
-                        mDelegate.stopRecognition(modelHandle);
+                    // If the activity state is INTERCEPTED, we skip delegating the command, but
+                    // still consider the call valid.
+                    if (modelState.activityState == ModelState.Activity.INTERCEPTED) {
+                        modelState.activityState = ModelState.Activity.LOADED;
+                        return;
                     }
-                    modelState.setActivityState(ModelState.Activity.LOADED);
                 } catch (Exception e) {
                     throw handleException(e);
                 }
             }
+
+            // Calling the delegate's stop must be done without the lock.
+            try {
+                mDelegate.stopRecognition(modelHandle);
+            } catch (Exception e) {
+                throw handleException(e);
+            }
+
+            synchronized (SoundTriggerMiddlewareValidation.this) {
+                ModelState modelState = mLoadedModels.get(modelHandle);
+                if (modelState == null) {
+                    // The model was unloaded while we let go of the lock.
+                    return;
+                }
+
+                // After the call, the state is LOADED, unless it has been first preempted.
+                if (modelState.activityState != ModelState.Activity.PREEMPTED) {
+                    modelState.activityState = ModelState.Activity.LOADED;
+                }
+            }
         }
 
         @Override
@@ -562,7 +532,7 @@
                 try {
                     // If the activity state is LOADED or INTERCEPTED, we skip delegating the
                     // command, but still consider the call valid.
-                    if (modelState.getActivityState() == ModelState.Activity.ACTIVE) {
+                    if (modelState.activityState == ModelState.Activity.ACTIVE) {
                         mDelegate.forceRecognitionEvent(modelHandle);
                     }
                 } catch (Exception e) {
@@ -644,7 +614,7 @@
                 try {
                     ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle,
                             modelParam);
-                    modelState.updateParameterSupport(modelParam, result);
+                    modelState.parameterSupport.put(modelParam, result);
                     return result;
                 } catch (Exception e) {
                     throw handleException(e);
@@ -702,7 +672,7 @@
                 for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
                     pw.print(entry.getKey());
                     pw.print('\t');
-                    pw.print(entry.getValue().getActivityState().name());
+                    pw.print(entry.getValue().activityState.name());
                     pw.print('\t');
                     pw.print(entry.getValue().description);
                     pw.println();
@@ -732,70 +702,79 @@
             }
 
             @Override
-        public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) {
-            // We cannot obtain a lock on SoundTriggerMiddlewareValidation.this, since this call
-            // might be coming from the audio server (via setCaptureState()) while it is holding
-            // a lock that is also acquired while loading / unloading models. Thus, we require a
-            // strict locking order here, where obtaining our lock must always come first.
-            // To avoid this problem, we use an atomic model activity state. There is a risk of the
-            // model not being in the mLoadedModels map here, since it might have been stopped /
-            // unloaded while the event was in flight.
-            ModelState modelState = mLoadedModels.get(modelHandle);
-            if (modelState != null) {
-                if (event.status != RecognitionStatus.FORCED) {
-                    modelState.setActivityState(ModelState.Activity.LOADED);
-                }
-                try {
-                    mCallback.onRecognition(modelHandle, event);
-                } catch (Exception e) {
-                    // Dead client will be handled by binderDied() - no need to handle here.
-                    // In any case, client callbacks are considered best effort.
-                    Log.e(TAG, "Client callback exception.", e);
+            public void onRecognition(int modelHandle, @NonNull RecognitionEvent event,
+                    int captureSession) {
+                synchronized (SoundTriggerMiddlewareValidation.this) {
+                    ModelState modelState = mLoadedModels.get(modelHandle);
                     if (event.status != RecognitionStatus.FORCED) {
-                        modelState.setActivityState(ModelState.Activity.INTERCEPTED);
+                        modelState.activityState = ModelState.Activity.LOADED;
+                    }
+                }
+
+                // Calling the delegate callback must be done outside the lock.
+                try {
+                    mCallback.onRecognition(modelHandle, event, captureSession);
+                } catch (Exception e) {
+                    Log.w(TAG, "Client callback exception.", e);
+                    synchronized (SoundTriggerMiddlewareValidation.this) {
+                        ModelState modelState = mLoadedModels.get(modelHandle);
+                        if (event.status != RecognitionStatus.FORCED) {
+                            modelState.activityState = ModelState.Activity.INTERCEPTED;
+                        }
                     }
                 }
             }
-        }
 
-        @Override
-        public void onPhraseRecognition(int modelHandle, @NonNull PhraseRecognitionEvent event) {
-            // We cannot obtain a lock on SoundTriggerMiddlewareValidation.this, since this call
-            // might be coming from the audio server (via setCaptureState()) while it is holding
-            // a lock that is also acquired while loading / unloading models. Thus, we require a
-            // strict locking order here, where obtaining our lock must always come first.
-            // To avoid this problem, we use an atomic model activity state. There is a risk of the
-            // model not being in the mLoadedModels map here, since it might have been stopped /
-            // unloaded while the event was in flight.
-            ModelState modelState = mLoadedModels.get(modelHandle);
-            if (modelState != null) {
-                if (event.common.status != RecognitionStatus.FORCED) {
-                        modelState.setActivityState(ModelState.Activity.LOADED);
+            @Override
+            public void onPhraseRecognition(int modelHandle,
+                    @NonNull PhraseRecognitionEvent event, int captureSession) {
+                synchronized (SoundTriggerMiddlewareValidation.this) {
+                    ModelState modelState = mLoadedModels.get(modelHandle);
+                    if (event.common.status != RecognitionStatus.FORCED) {
+                        modelState.activityState = ModelState.Activity.LOADED;
+                    }
                 }
+
+                // Calling the delegate callback must be done outside the lock.
                 try {
-                    mCallback.onPhraseRecognition(modelHandle, event);
+                    mCallback.onPhraseRecognition(modelHandle, event, captureSession);
                 } catch (Exception e) {
+                    Log.w(TAG, "Client callback exception.", e);
+                    synchronized (SoundTriggerMiddlewareValidation.this) {
+                        ModelState modelState = mLoadedModels.get(modelHandle);
+                        if (event.common.status != RecognitionStatus.FORCED) {
+                            modelState.activityState = ModelState.Activity.INTERCEPTED;
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void onModelUnloaded(int modelHandle) {
+                synchronized (SoundTriggerMiddlewareValidation.this) {
+                    ModelState modelState = mLoadedModels.get(modelHandle);
+                    modelState.activityState = ModelState.Activity.PREEMPTED;
+                }
+
+                // Calling the delegate callback must be done outside the lock.
+                try {
+                    mCallback.onModelUnloaded(modelHandle);
+                } catch (Exception e) {
+                    Log.w(TAG, "Client callback exception.", e);
+                }
+            }
+
+            @Override
+            public void onResourcesAvailable() {
+                // Not locking to avoid deadlocks (not affecting any state).
+                try {
+                    mCallback.onResourcesAvailable();
+                } catch (RemoteException e) {
                     // Dead client will be handled by binderDied() - no need to handle here.
                     // In any case, client callbacks are considered best effort.
                     Log.e(TAG, "Client callback exception.", e);
-                    if (event.common.status != RecognitionStatus.FORCED) {
-                        modelState.setActivityState(ModelState.Activity.INTERCEPTED);
-                    }
                 }
             }
-        }
-
-        @Override
-        public void onRecognitionAvailabilityChange(boolean available) {
-            // Not locking to avoid deadlocks (not affecting any state).
-            try {
-                mCallback.onRecognitionAvailabilityChange(available);
-            } catch (RemoteException e) {
-                // Dead client will be handled by binderDied() - no need to handle here.
-                // In any case, client callbacks are considered best effort.
-                Log.e(TAG, "Client callback exception.", e);
-            }
-        }
 
             @Override
             public void onModuleDied() {
@@ -820,8 +799,7 @@
                         // Gracefully stop all active recognitions and unload the models.
                         for (Map.Entry<Integer, ModelState> entry :
                                 mLoadedModels.entrySet()) {
-                            if (entry.getValue().getActivityState()
-                                    == ModelState.Activity.ACTIVE) {
+                            if (entry.getValue().activityState == ModelState.Activity.ACTIVE) {
                                 mDelegate.stopRecognition(entry.getKey());
                             }
                             mDelegate.unloadModel(entry.getKey());
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 02d978d..f211158 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -18,30 +18,24 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
-import android.hardware.soundtrigger.V2_2.ISoundTriggerHw;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.RecognitionStatus;
-import android.media.soundtrigger_middleware.SoundModel;
-import android.media.soundtrigger_middleware.SoundModelType;
-import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
-import android.media.soundtrigger_middleware.Status;
 import android.os.IBinder;
-import android.os.IHwBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -71,9 +65,8 @@
  * <li>There is no binder instance associated with this implementation. Do not call asBinder().
  * <li>The implementation may throw a {@link RecoverableException} to indicate non-fatal,
  * recoverable faults. The error code would one of the
- * {@link android.media.soundtrigger_middleware.Status} constants. Any other exception
- * thrown should be regarded as a bug in the implementation or one of its dependencies
- * (assuming correct usage).
+ * {@link android.media.soundtrigger.Status} constants. Any other exception thrown should be
+ * regarded as a bug in the implementation or one of its dependencies (assuming correct usage).
  * <li>The implementation is designed for testability by featuring dependency injection (the
  * underlying HAL driver instances are passed to the ctor) and by minimizing dependencies
  * on Android runtime.
@@ -88,15 +81,13 @@
  *
  * @hide
  */
-class SoundTriggerModule implements IHwBinder.DeathRecipient {
+class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.GlobalCallback {
     static private final String TAG = "SoundTriggerModule";
-    @NonNull private HalFactory mHalFactory;
-    @NonNull private ISoundTriggerHw2 mHalService;
+    @NonNull private final HalFactory mHalFactory;
+    @NonNull private ISoundTriggerHal mHalService;
     @NonNull private final SoundTriggerMiddlewareImpl.AudioSessionProvider mAudioSessionProvider;
     private final Set<Session> mActiveSessions = new HashSet<>();
-    private int mNumLoadedModels = 0;
-    private SoundTriggerModuleProperties mProperties;
-    private boolean mRecognitionAvailable;
+    private Properties mProperties;
 
     /**
      * Ctor.
@@ -110,9 +101,6 @@
         mAudioSessionProvider = audioSessionProvider;
 
         attachToHal();
-        mProperties = ConversionUtil.hidl2aidlProperties(mHalService.getProperties());
-        // We conservatively assume that external capture is active until explicitly told otherwise.
-        mRecognitionAvailable = mProperties.concurrentCapture;
     }
 
     /**
@@ -140,50 +128,13 @@
      * @return The properties structure.
      */
     synchronized @NonNull
-    SoundTriggerModuleProperties getProperties() {
+    Properties getProperties() {
         return mProperties;
     }
 
-    /**
-     * Notify the module that external capture has started / finished, using the same input device
-     * used for recognition.
-     * If the underlying driver does not support recognition while capturing, capture will be
-     * aborted, and the recognition callback will receive and abort event. In addition, all active
-     * clients will be notified of the change in state.
-     *
-     * @param active true iff external capture is active.
-     */
-    void setExternalCaptureState(boolean active) {
-        // We should never invoke callbacks while holding the lock, since this may deadlock with
-        // forward calls. Thus, we first gather all the callbacks we need to invoke while holding
-        // the lock, but invoke them after releasing it.
-        List<Runnable> callbacks = new LinkedList<>();
-
-        synchronized (this) {
-            if (mProperties.concurrentCapture) {
-                // If we support concurrent capture, we don't care about any of this.
-                return;
-            }
-            mRecognitionAvailable = !active;
-            if (!mRecognitionAvailable) {
-                // Our module does not support recognition while a capture is active -
-                // need to abort all active recognitions.
-                for (Session session : mActiveSessions) {
-                    session.abortActiveRecognitions(callbacks);
-                }
-            }
-        }
-        for (Runnable callback : callbacks) {
-            callback.run();
-        }
-        for (Session session : mActiveSessions) {
-            session.notifyRecognitionAvailability();
-        }
-    }
-
     @Override
-    public void serviceDied(long cookie) {
-        Log.w(TAG, String.format("Underlying HAL driver died."));
+    public void binderDied() {
+        Log.w(TAG, "Underlying HAL driver died.");
         List<ISoundTriggerCallback> callbacks;
         synchronized (this) {
             callbacks = new ArrayList<>(mActiveSessions.size());
@@ -207,20 +158,19 @@
      * Resets the transient state of this object.
      */
     private void reset() {
+        mHalService.detach();
         attachToHal();
-        // We conservatively assume that external capture is active until explicitly told otherwise.
-        mRecognitionAvailable = mProperties.concurrentCapture;
-        mNumLoadedModels = 0;
     }
 
     /**
      * Attached to the HAL service via factory.
      */
     private void attachToHal() {
-        mHalService = new SoundTriggerHw2Enforcer(
-                new SoundTriggerHw2Watchdog(
-                        new SoundTriggerHw2Compat(mHalFactory.create())));
-        mHalService.linkToDeath(this, 0);
+        mHalService = new SoundTriggerHalEnforcer(
+                new SoundTriggerHalWatchdog(mHalFactory.create()));
+        mHalService.linkToDeath(this);
+        mHalService.registerCallback(this);
+        mProperties = mHalService.getProperties();
     }
 
     /**
@@ -232,6 +182,25 @@
         mActiveSessions.remove(session);
     }
 
+    @Override
+    public void onResourcesAvailable() {
+        List<ISoundTriggerCallback> callbacks;
+        synchronized (this) {
+            callbacks = new ArrayList<>(mActiveSessions.size());
+            for (Session session : mActiveSessions) {
+                callbacks.add(session.mCallback);
+            }
+        }
+        // Trigger the callbacks outside of the lock to avoid deadlocks.
+        for (ISoundTriggerCallback callback : callbacks) {
+            try {
+                callback.onResourcesAvailable();
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+    }
+
     /** State of a single sound model. */
     private enum ModelState {
         /** Initial state, until load() is called. */
@@ -249,7 +218,7 @@
      */
     private class Session implements ISoundTriggerModule {
         private ISoundTriggerCallback mCallback;
-        private Map<Integer, Model> mLoadedModels = new HashMap<>();
+        private final Map<Integer, Model> mLoadedModels = new HashMap<>();
 
         /**
          * Ctor.
@@ -258,7 +227,6 @@
          */
         private Session(@NonNull ISoundTriggerCallback callback) {
             mCallback = callback;
-            notifyRecognitionAvailability();
         }
 
         @Override
@@ -274,95 +242,65 @@
 
         @Override
         public int loadModel(@NonNull SoundModel model) {
-            // We must do this outside the lock, to avoid possible deadlocks with the remote process
-            // that provides the audio sessions, which may also be calling into us.
-            SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession =
-                    mAudioSessionProvider.acquireSession();
-
-            try {
-                synchronized (SoundTriggerModule.this) {
-                    checkValid();
-                    if (mNumLoadedModels == mProperties.maxSoundModels) {
-                        throw new RecoverableException(Status.RESOURCE_CONTENTION,
-                                "Maximum number of models loaded.");
-                    }
-                    Model loadedModel = new Model();
-                    int result = loadedModel.load(model, audioSession);
-                    ++mNumLoadedModels;
-                    return result;
-                }
-            } catch (Exception e) {
-                // We must do this outside the lock, to avoid possible deadlocks with the remote
-                // process that provides the audio sessions, which may also be calling into us.
+            synchronized (SoundTriggerModule.this) {
+                SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession =
+                        mAudioSessionProvider.acquireSession();
                 try {
-                    mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
-                } catch (Exception ee) {
-                    Log.e(TAG, "Failed to release session.", ee);
+                    checkValid();
+                    Model loadedModel = new Model();
+                    return loadedModel.load(model, audioSession);
+                } catch (Exception e) {
+                    // We must do this outside the lock, to avoid possible deadlocks with the remote
+                    // process that provides the audio sessions, which may also be calling into us.
+                    try {
+                        mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+                    } catch (Exception ee) {
+                        Log.e(TAG, "Failed to release session.", ee);
+                    }
+                    throw e;
                 }
-                throw e;
             }
         }
 
         @Override
         public int loadPhraseModel(@NonNull PhraseSoundModel model) {
-            // We must do this outside the lock, to avoid possible deadlocks with the remote process
-            // that provides the audio sessions, which may also be calling into us.
-            SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession =
-                    mAudioSessionProvider.acquireSession();
-
-            try {
-                synchronized (SoundTriggerModule.this) {
+            synchronized (SoundTriggerModule.this) {
+                SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession =
+                        mAudioSessionProvider.acquireSession();
+                try {
                     checkValid();
-                    if (mNumLoadedModels == mProperties.maxSoundModels) {
-                        throw new RecoverableException(Status.RESOURCE_CONTENTION,
-                                "Maximum number of models loaded.");
-                    }
                     Model loadedModel = new Model();
                     int result = loadedModel.load(model, audioSession);
-                    ++mNumLoadedModels;
                     Log.d(TAG, String.format("loadPhraseModel()->%d", result));
                     return result;
+                } catch (Exception e) {
+                    // We must do this outside the lock, to avoid possible deadlocks with the remote
+                    // process that provides the audio sessions, which may also be calling into us.
+                    try {
+                        mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+                    } catch (Exception ee) {
+                        Log.e(TAG, "Failed to release session.", ee);
+                    }
+                    throw e;
                 }
-            } catch (Exception e) {
-                // We must do this outside the lock, to avoid possible deadlocks with the remote
-                // process that provides the audio sessions, which may also be calling into us.
-                try {
-                    mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
-                } catch (Exception ee) {
-                    Log.e(TAG, "Failed to release session.", ee);
-                }
-                throw e;
             }
         }
 
         @Override
         public void unloadModel(int modelHandle) {
-            int sessionId;
             synchronized (SoundTriggerModule.this) {
+                int sessionId;
                 checkValid();
                 sessionId = mLoadedModels.get(modelHandle).unload();
-                --mNumLoadedModels;
+                mAudioSessionProvider.releaseSession(sessionId);
             }
-
-            // We must do this outside the lock, to avoid possible deadlocks with the remote process
-            // that provides the audio sessions, which may also be calling into us.
-            mAudioSessionProvider.releaseSession(sessionId);
         }
 
         @Override
         public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) {
-            // We should never invoke callbacks while holding the lock, since this may deadlock with
-            // forward calls. Thus, we first gather all the callbacks we need to invoke while holding
-            // the lock, but invoke them after releasing it.
-            List<Runnable> callbacks = new LinkedList<>();
-
             synchronized (SoundTriggerModule.this) {
                 checkValid();
-                mLoadedModels.get(modelHandle).startRecognition(config, callbacks);
-            }
-
-            for (Runnable callback : callbacks) {
-                callback.run();
+                mLoadedModels.get(modelHandle).startRecognition(config);
             }
         }
 
@@ -407,27 +345,6 @@
         }
 
         /**
-         * Abort all currently active recognitions.
-         * @param callbacks Will be appended with a list of callbacks that need to be invoked
-         *                  after this method returns, without holding the module lock.
-         */
-        private void abortActiveRecognitions(@NonNull List<Runnable> callbacks) {
-            for (Model model : mLoadedModels.values()) {
-                model.abortActiveRecognition(callbacks);
-            }
-        }
-
-        private void notifyRecognitionAvailability() {
-            try {
-                mCallback.onRecognitionAvailabilityChange(mRecognitionAvailable);
-            } catch (RemoteException e) {
-                // Dead client will be handled by binderDied() - no need to handle here.
-                // In any case, client callbacks are considered best effort.
-                Log.e(TAG, "Client callback execption.", e);
-            }
-        }
-
-        /**
          * The underlying module HAL is dead.
          * @return The client callback that needs to be invoked to notify the client.
          */
@@ -455,10 +372,9 @@
          *
          * All model-based operations are delegated to this class and implemented here.
          */
-        private class Model implements ISoundTriggerHw2.Callback {
+        private class Model implements ISoundTriggerHal.ModelCallback {
             public int mHandle;
             private ModelState mState = ModelState.INIT;
-            private int mModelType = SoundModelType.UNKNOWN;
             private SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession mSession;
 
             private @NonNull
@@ -473,11 +389,8 @@
 
             private int load(@NonNull SoundModel model,
                     SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
-                mModelType = model.type;
                 mSession = audioSession;
-                ISoundTriggerHw.SoundModel hidlModel = ConversionUtil.aidl2hidlSoundModel(model);
-
-                mHandle = mHalService.loadSoundModel(hidlModel, this, 0);
+                mHandle = mHalService.loadSoundModel(model, this);
                 setState(ModelState.LOADED);
                 mLoadedModels.put(mHandle, this);
                 return mHandle;
@@ -485,12 +398,8 @@
 
             private int load(@NonNull PhraseSoundModel model,
                     SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
-                mModelType = model.common.type;
                 mSession = audioSession;
-                ISoundTriggerHw.PhraseSoundModel hidlModel =
-                        ConversionUtil.aidl2hidlPhraseSoundModel(model);
-
-                mHandle = mHalService.loadPhraseSoundModel(hidlModel, this, 0);
+                mHandle = mHalService.loadPhraseSoundModel(model, this);
 
                 setState(ModelState.LOADED);
                 mLoadedModels.put(mHandle, this);
@@ -507,18 +416,9 @@
                 return mSession.mSessionHandle;
             }
 
-            private void startRecognition(@NonNull RecognitionConfig config,
-                    @NonNull List<Runnable> callbacks) {
-                if (!mRecognitionAvailable) {
-                    // Recognition is unavailable - send an abort event immediately.
-                    callbacks.add(this::notifyAbort);
-                    return;
-                }
-                android.hardware.soundtrigger.V2_3.RecognitionConfig hidlConfig =
-                        ConversionUtil.aidl2hidlRecognitionConfig(config);
-                hidlConfig.base.header.captureDevice = mSession.mDeviceHandle;
-                hidlConfig.base.header.captureHandle = mSession.mIoHandle;
-                mHalService.startRecognition(mHandle, hidlConfig, this, 0);
+            private void startRecognition(@NonNull RecognitionConfig config) {
+                mHalService.startRecognition(mHandle, mSession.mDeviceHandle,
+                        mSession.mIoHandle, config);
                 setState(ModelState.ACTIVE);
             }
 
@@ -537,7 +437,7 @@
                     // This call is idempotent in order to avoid races.
                     return;
                 }
-                mHalService.getModelState(mHandle);
+                mHalService.forceRecognitionEvent(mHandle);
             }
 
 
@@ -553,78 +453,24 @@
 
             @Nullable
             private ModelParameterRange queryModelParameterSupport(int modelParam) {
-                return ConversionUtil.hidl2aidlModelParameterRange(
-                        mHalService.queryParameter(mHandle,
-                                ConversionUtil.aidl2hidlModelParameter(modelParam)));
-            }
-
-            /**
-             * Abort the recognition, if active.
-             * @param callbacks Will be appended with a list of callbacks that need to be invoked
-             *                  after this method returns, without holding the module lock.
-             */
-            private void abortActiveRecognition(List<Runnable> callbacks) {
-                // If we're inactive, do nothing.
-                if (getState() != ModelState.ACTIVE) {
-                    return;
-                }
-                // Stop recognition.
-                stopRecognition();
-
-                // Notify the client that recognition has been aborted.
-                callbacks.add(this::notifyAbort);
-            }
-
-            /** Notify the client that recognition has been aborted. */
-            private void notifyAbort() {
-                try {
-                    switch (mModelType) {
-                        case SoundModelType.GENERIC: {
-                            android.media.soundtrigger_middleware.RecognitionEvent event =
-                                    newEmptyRecognitionEvent();
-                            event.status =
-                                    android.media.soundtrigger_middleware.RecognitionStatus.ABORTED;
-                            event.type = SoundModelType.GENERIC;
-                            mCallback.onRecognition(mHandle, event);
-                        }
-                        break;
-
-                        case SoundModelType.KEYPHRASE: {
-                            android.media.soundtrigger_middleware.PhraseRecognitionEvent event =
-                                    newEmptyPhraseRecognitionEvent();
-                            event.common.status =
-                                    android.media.soundtrigger_middleware.RecognitionStatus.ABORTED;
-                            event.common.type = SoundModelType.KEYPHRASE;
-                            mCallback.onPhraseRecognition(mHandle, event);
-                        }
-                        break;
-
-                        default:
-                            Log.e(TAG, "Unknown model type: " + mModelType);
-
-                    }
-                } catch (RemoteException e) {
-                    // Dead client will be handled by binderDied() - no need to handle here.
-                    // In any case, client callbacks are considered best effort.
-                    Log.e(TAG, "Client callback execption.", e);
-                }
+                return mHalService.queryParameter(mHandle, modelParam);
             }
 
             @Override
-            public void recognitionCallback(
-                    @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent,
-                    int cookie) {
-                RecognitionEvent aidlEvent =
-                        ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent);
-                aidlEvent.captureSession = mSession.mSessionHandle;
+            public void recognitionCallback(int modelHandle,
+                    @NonNull RecognitionEvent recognitionEvent) {
+                ISoundTriggerCallback callback;
                 synchronized (SoundTriggerModule.this) {
-                    if (aidlEvent.status != RecognitionStatus.FORCED) {
+                    if (recognitionEvent.status != RecognitionStatus.FORCED) {
                         setState(ModelState.LOADED);
                     }
+                    callback = mCallback;
                 }
                 // The callback must be invoked outside of the lock.
                 try {
-                    mCallback.onRecognition(mHandle, aidlEvent);
+                    if (callback != null) {
+                        callback.onRecognition(mHandle, recognitionEvent, mSession.mSessionHandle);
+                    }
                 } catch (RemoteException e) {
                     // We're not expecting any exceptions here.
                     throw e.rethrowAsRuntimeException();
@@ -632,22 +478,40 @@
             }
 
             @Override
-            public void phraseRecognitionCallback(
-                    @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent,
-                    int cookie) {
-                PhraseRecognitionEvent aidlEvent =
-                        ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent);
-                aidlEvent.common.captureSession = mSession.mSessionHandle;
-
+            public void phraseRecognitionCallback(int modelHandle,
+                    @NonNull PhraseRecognitionEvent phraseRecognitionEvent) {
+                ISoundTriggerCallback callback;
                 synchronized (SoundTriggerModule.this) {
-                    if (aidlEvent.common.status != RecognitionStatus.FORCED) {
+                    if (phraseRecognitionEvent.common.status != RecognitionStatus.FORCED) {
                         setState(ModelState.LOADED);
                     }
+                    callback = mCallback;
                 }
 
                 // The callback must be invoked outside of the lock.
                 try {
-                    mCallback.onPhraseRecognition(mHandle, aidlEvent);
+                    if (callback != null) {
+                        mCallback.onPhraseRecognition(mHandle, phraseRecognitionEvent,
+                                mSession.mSessionHandle);
+                    }
+                } catch (RemoteException e) {
+                    // We're not expecting any exceptions here.
+                    throw e.rethrowAsRuntimeException();
+                }
+            }
+
+            @Override
+            public void modelUnloaded(int modelHandle) {
+                ISoundTriggerCallback callback;
+                synchronized (SoundTriggerModule.this) {
+                    callback = mCallback;
+                }
+
+                // The callback must be invoked outside of the lock.
+                try {
+                    if (callback != null) {
+                        callback.onModelUnloaded(modelHandle);
+                    }
                 } catch (RemoteException e) {
                     // We're not expecting any exceptions here.
                     throw e.rethrowAsRuntimeException();
@@ -655,33 +519,4 @@
             }
         }
     }
-
-    /**
-     * Creates a default-initialized recognition event.
-     *
-     * Non-nullable object fields are default constructed.
-     * Non-nullable array fields are initialized to 0 length.
-     *
-     * @return The event.
-     */
-    private static RecognitionEvent newEmptyRecognitionEvent() {
-        RecognitionEvent result = new RecognitionEvent();
-        result.data = new byte[0];
-        return result;
-    }
-
-    /**
-     * Creates a default-initialized phrase recognition event.
-     *
-     * Non-nullable object fields are default constructed.
-     * Non-nullable array fields are initialized to 0 length.
-     *
-     * @return The event.
-     */
-    private static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
-        PhraseRecognitionEvent result = new PhraseRecognitionEvent();
-        result.common = newEmptyRecognitionEvent();
-        result.phraseExtras = new PhraseRecognitionExtra[0];
-        return result;
-    }
 }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
index e05c468..4d52121 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
@@ -17,21 +17,18 @@
 package com.android.server.soundtrigger_middleware;
 
 import android.annotation.Nullable;
-import android.media.soundtrigger_middleware.ConfidenceLevel;
-import android.media.soundtrigger_middleware.ModelParameter;
-import android.media.soundtrigger_middleware.Phrase;
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionMode;
-import android.media.soundtrigger_middleware.SoundModel;
-import android.media.soundtrigger_middleware.SoundModelType;
-
-import com.android.internal.util.Preconditions;
+import android.media.soundtrigger.ConfidenceLevel;
+import android.media.soundtrigger.ModelParameter;
+import android.media.soundtrigger.Phrase;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionMode;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
 
 import java.util.Objects;
 import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * Utilities for asserting the validity of various data types used by this module.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 357c232..e751a7b 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -42,6 +42,7 @@
 import com.android.server.timezonedetector.ConfigurationChangeListener;
 import com.android.server.timezonedetector.ReferenceWithHistory;
 
+import java.time.Duration;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Objects;
@@ -321,12 +322,16 @@
         ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
         ipw.println("mEnvironment.isAutoTimeDetectionEnabled()="
                 + mEnvironment.isAutoTimeDetectionEnabled());
-        ipw.println("mEnvironment.elapsedRealtimeMillis()=" + mEnvironment.elapsedRealtimeMillis());
-        ipw.println("mEnvironment.systemClockMillis()=" + mEnvironment.systemClockMillis());
+        long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
+        ipw.printf("mEnvironment.elapsedRealtimeMillis()=%s (%s)\n",
+                Duration.ofMillis(elapsedRealtimeMillis), elapsedRealtimeMillis);
+        long systemClockMillis = mEnvironment.systemClockMillis();
+        ipw.printf("mEnvironment.systemClockMillis()=%s (%s)\n",
+                Instant.ofEpochMilli(systemClockMillis), systemClockMillis);
         ipw.println("mEnvironment.systemClockUpdateThresholdMillis()="
                 + mEnvironment.systemClockUpdateThresholdMillis());
         Instant autoTimeLowerBound = mEnvironment.autoTimeLowerBound();
-        ipw.printf("mEnvironment.autoTimeLowerBound()=%s(%s)\n",
+        ipw.printf("mEnvironment.autoTimeLowerBound()=%s (%s)\n",
                 autoTimeLowerBound, autoTimeLowerBound.toEpochMilli());
         String priorities =
                 Arrays.stream(mEnvironment.autoOriginPriorities())
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 5723e1d..ee30fa2 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -50,8 +50,6 @@
      */
     private final int mProcessId;
 
-    private boolean mIsForeground;
-
     /**
      * All the clients that share the same resource would be under the same group id.
      *
@@ -90,6 +88,12 @@
     private int mUsingCiCamId = INVALID_RESOURCE_ID;
 
     /**
+     * If the priority is overwritten through
+     * {@link TunerResourceManagerService#setPriority(int, int)}.
+     */
+    private boolean mIsPriorityOverwritten = false;
+
+    /**
      * Optional arbitrary priority value given by the client.
      *
      * <p>This value can override the default priorotiy calculated from
@@ -121,17 +125,10 @@
     }
 
     /**
-     * Set the current isForeground status.
+     * If the client priority is overwrttien.
      */
-    public void setForeground(boolean isForeground) {
-        mIsForeground = isForeground;
-    }
-
-    /**
-     * Get the previous recorded isForeground status.
-     */
-    public boolean isForeground() {
-        return mIsForeground;
+    public boolean isPriorityOverwritten() {
+        return mIsPriorityOverwritten;
     }
 
     public int getGroupId() {
@@ -153,6 +150,17 @@
         mPriority = priority;
     }
 
+    /**
+     * Overwrite the client priority.
+     */
+    public void overwritePriority(int priority) {
+        if (priority < 0) {
+            return;
+        }
+        mIsPriorityOverwritten = true;
+        mPriority = priority;
+    }
+
     public void setNiceValue(int niceValue) {
         mNiceValue = niceValue;
     }
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 988582d..0c04b07 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -507,9 +507,8 @@
                                               .useCase(profile.useCase)
                                               .processId(pid)
                                               .build();
-        clientProfile.setForeground(checkIsForeground(pid));
         clientProfile.setPriority(
-                getClientPriority(profile.useCase, clientProfile.isForeground()));
+                getClientPriority(profile.useCase, checkIsForeground(pid)));
 
         addClientProfile(clientId[0], clientProfile, listener);
     }
@@ -547,8 +546,7 @@
             return false;
         }
 
-        profile.setForeground(checkIsForeground(profile.getProcessId()));
-        profile.setPriority(priority);
+        profile.overwritePriority(priority);
         profile.setNiceValue(niceValue);
 
         return true;
@@ -694,7 +692,7 @@
                 } else if (grantingFrontendHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
                     // Record the frontend id with the lowest client priority among all the
                     // in use frontends when no available frontend has been found.
-                    int priority = getOwnerClientPriority(fr.getOwnerClientId());
+                    int priority = updateAndGetOwnerClientPriority(fr.getOwnerClientId());
                     if (currentLowestPriority > priority) {
                         inUseLowestPriorityFrHandle = fr.getHandle();
                         currentLowestPriority = priority;
@@ -760,7 +758,7 @@
             } else {
                 // Record the lnb id with the lowest client priority among all the
                 // in use lnb when no available lnb has been found.
-                int priority = getOwnerClientPriority(lnb.getOwnerClientId());
+                int priority = updateAndGetOwnerClientPriority(lnb.getOwnerClientId());
                 if (currentLowestPriority > priority) {
                     inUseLowestPriorityLnbHandle = lnb.getHandle();
                     currentLowestPriority = priority;
@@ -818,7 +816,7 @@
         }
         for (int ownerId : cas.getOwnerClientIds()) {
             // Record the client id with lowest priority that is using the current Cas system.
-            int priority = getOwnerClientPriority(ownerId);
+            int priority = updateAndGetOwnerClientPriority(ownerId);
             if (currentLowestPriority > priority) {
                 lowestPriorityOwnerId = ownerId;
                 currentLowestPriority = priority;
@@ -867,7 +865,7 @@
         }
         for (int ownerId : ciCam.getOwnerClientIds()) {
             // Record the client id with lowest priority that is using the current Cas system.
-            int priority = getOwnerClientPriority(ownerId);
+            int priority = updateAndGetOwnerClientPriority(ownerId);
             if (currentLowestPriority > priority) {
                 lowestPriorityOwnerId = ownerId;
                 currentLowestPriority = priority;
@@ -966,18 +964,17 @@
     }
 
     @VisibleForTesting
-    // This mothod is to sync up the request client's foreground/background status and update
-    // the client priority accordingly whenever new resource request comes in.
-    protected void clientPriorityUpdateOnRequest(ClientProfile requestProfile) {
-        int pid = requestProfile.getProcessId();
-        boolean currentIsForeground = checkIsForeground(pid);
-        if (requestProfile.isForeground() == currentIsForeground) {
+    // This mothod is to sync up the request/holder client's foreground/background status and update
+    // the client priority accordingly whenever a new resource request comes in.
+    protected void clientPriorityUpdateOnRequest(ClientProfile profile) {
+        if (profile.isPriorityOverwritten()) {
             // To avoid overriding the priority set through updateClientPriority API.
             return;
         }
-        requestProfile.setForeground(currentIsForeground);
-        requestProfile.setPriority(
-                getClientPriority(requestProfile.getUseCase(), currentIsForeground));
+        int pid = profile.getProcessId();
+        boolean currentIsForeground = checkIsForeground(pid);
+        profile.setPriority(
+                getClientPriority(profile.getUseCase(), currentIsForeground));
     }
 
     @VisibleForTesting
@@ -1154,13 +1151,15 @@
     }
 
     /**
-     * Get the owner client's priority.
+     * Update and get the owner client's priority.
      *
      * @param clientId the owner client id.
      * @return the priority of the owner client.
      */
-    private int getOwnerClientPriority(int clientId) {
-        return getClientProfile(clientId).getPriority();
+    private int updateAndGetOwnerClientPriority(int clientId) {
+        ClientProfile profile = getClientProfile(clientId);
+        clientPriorityUpdateOnRequest(profile);
+        return profile.getPriority();
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/utils/OWNERS b/services/core/java/com/android/server/utils/OWNERS
index cc41f61..62afcc8 100644
--- a/services/core/java/com/android/server/utils/OWNERS
+++ b/services/core/java/com/android/server/utils/OWNERS
@@ -1,7 +1,7 @@
 per-file Snappable.java = file:/services/core/java/com/android/server/pm/OWNERS
 per-file Snappable.java = shombert@google.com
-per-file SnapShot* = file:/services/core/java/com/android/server/pm/OWNERS
-per-file SnapShot* = shombert@google.com
+per-file Snapshot* = file:/services/core/java/com/android/server/pm/OWNERS
+per-file Snapshot* = shombert@google.com
 per-file Watchable* = file:/services/core/java/com/android/server/pm/OWNERS
 per-file Watchable* = shombert@google.com
 per-file Watched* = file:/services/core/java/com/android/server/pm/OWNERS
diff --git a/services/core/java/com/android/server/vcn/OWNERS b/services/core/java/com/android/server/vcn/OWNERS
index 33b9f0f..2441e77 100644
--- a/services/core/java/com/android/server/vcn/OWNERS
+++ b/services/core/java/com/android/server/vcn/OWNERS
@@ -3,5 +3,5 @@
 benedictwong@google.com
 ckesting@google.com
 evitayan@google.com
+junyin@google.com
 nharold@google.com
-jchalard@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7713320..2c56359 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1816,26 +1816,26 @@
 
     @Override
     public void onUnlockUser(final int userId) {
-        TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
-        t.traceBegin("on-unlock-user-" + userId);
-        try {
-            synchronized (mLock) {
-                if (mCurrentUserId == userId) {
-                    if (mWaitingForUnlock) {
-                        // the desired wallpaper is not direct-boot aware, load it now
-                        final WallpaperData systemWallpaper =
-                                getWallpaperSafeLocked(userId, FLAG_SYSTEM);
-                        switchWallpaper(systemWallpaper, null);
-                        notifyCallbacksLocked(systemWallpaper);
-                    }
+        synchronized (mLock) {
+            if (mCurrentUserId == userId) {
+                if (mWaitingForUnlock) {
+                    // the desired wallpaper is not direct-boot aware, load it now
+                    final WallpaperData systemWallpaper =
+                            getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+                    switchWallpaper(systemWallpaper, null);
+                    notifyCallbacksLocked(systemWallpaper);
+                }
 
-                    // Make sure that the SELinux labeling of all the relevant files is correct.
-                    // This corrects for mislabeling bugs that might have arisen from move-to
-                    // operations involving the wallpaper files.  This isn't timing-critical,
-                    // so we do it in the background to avoid holding up the user unlock operation.
-                    if (!mUserRestorecon.get(userId)) {
-                        mUserRestorecon.put(userId, true);
-                        Runnable relabeler = () -> {
+                // Make sure that the SELinux labeling of all the relevant files is correct.
+                // This corrects for mislabeling bugs that might have arisen from move-to
+                // operations involving the wallpaper files.  This isn't timing-critical,
+                // so we do it in the background to avoid holding up the user unlock operation.
+                if (!mUserRestorecon.get(userId)) {
+                    mUserRestorecon.put(userId, true);
+                    Runnable relabeler = () -> {
+                        final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+                        t.traceBegin("Wallpaper_selinux_restorecon-" + userId);
+                        try {
                             final File wallpaperDir = getWallpaperDir(userId);
                             for (String filename : sPerUserFiles) {
                                 File f = new File(wallpaperDir, filename);
@@ -1843,13 +1843,13 @@
                                     SELinux.restorecon(f);
                                 }
                             }
-                        };
-                        BackgroundThread.getHandler().post(relabeler);
-                    }
+                        } finally {
+                            t.traceEnd();
+                        }
+                    };
+                    BackgroundThread.getHandler().post(relabeler);
                 }
             }
-        } finally {
-            t.traceEnd();
         }
     }
 
@@ -1868,7 +1868,7 @@
 
     void switchUser(int userId, IRemoteCallback reply) {
         TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
-        t.traceBegin("switch-user-" + userId);
+        t.traceBegin("Wallpaper_switch-user-" + userId);
         try {
             final WallpaperData systemWallpaper;
             final WallpaperData lockWallpaper;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index a24319f..d311640 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CALLBACK;
+import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK;
 import static android.os.Build.IS_USER;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -34,6 +36,7 @@
 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PKG;
 import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_STACKS;
 import static com.android.server.accessibility.AccessibilityTraceProto.ELAPSED_REALTIME_NANOS;
+import static com.android.server.accessibility.AccessibilityTraceProto.LOGGING_TYPE;
 import static com.android.server.accessibility.AccessibilityTraceProto.PROCESS_NAME;
 import static com.android.server.accessibility.AccessibilityTraceProto.THREAD_ID_NAME;
 import static com.android.server.accessibility.AccessibilityTraceProto.WHERE;
@@ -42,6 +45,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.utils.RegionUtils.forEachRect;
 
+import android.accessibilityservice.AccessibilityTrace;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
@@ -90,6 +94,7 @@
 import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.TraceBuffer;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
@@ -99,8 +104,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -116,21 +119,16 @@
     private static final String TAG = AccessibilityController.class.getSimpleName();
 
     private static final Object STATIC_LOCK = new Object();
-    static AccessibilityControllerInternal
+    static AccessibilityControllerInternalImpl
             getAccessibilityControllerInternal(WindowManagerService service) {
         return AccessibilityControllerInternalImpl.getInstance(service);
     }
 
-    private final AccessibilityTracing mAccessibilityTracing;
+    private final AccessibilityControllerInternalImpl mAccessibilityTracing;
     private final WindowManagerService mService;
     private static final Rect EMPTY_RECT = new Rect();
     private static final float[] sTempFloats = new float[9];
 
-    AccessibilityController(WindowManagerService service) {
-        mService = service;
-        mAccessibilityTracing = AccessibilityTracing.getInstance(service);
-    }
-
     private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
     private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
             new SparseArray<>();
@@ -138,10 +136,17 @@
     // Set to true if initializing window population complete.
     private boolean mAllObserversInitialized = true;
 
+    AccessibilityController(WindowManagerService service) {
+        mService = service;
+        mAccessibilityTracing =
+                AccessibilityController.getAccessibilityControllerInternal(service);
+    }
+
     boolean setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(
                     TAG + ".setMagnificationCallbacks",
+                    FLAGS_MAGNIFICATION_CALLBACK,
                     "displayId=" + displayId + "; callbacks={" + callbacks + "}");
         }
         boolean result = false;
@@ -172,25 +177,31 @@
 
     /**
      * Sets a callback for observing which windows are touchable for the purposes
-     * of accessibility on specified display.
+     * of accessibility on specified display. When a display is reparented and becomes
+     * an embedded one, the {@link WindowsForAccessibilityCallback#onDisplayReparented(int)}
+     * will notify the accessibility framework to remove the un-used window observer of
+     * this embedded display.
      *
      * @param displayId The logical display id.
      * @param callback The callback.
-     * @return {@code false} if display id is not valid or an embedded display.
+     * @return {@code false} if display id is not valid or an embedded display when the callback
+     * isn't null.
      */
     boolean setWindowsForAccessibilityCallback(int displayId,
             WindowsForAccessibilityCallback callback) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(
                     TAG + ".setWindowsForAccessibilityCallback",
+                    FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
                     "displayId=" + displayId + "; callback={" + callback + "}");
         }
-        final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
-        if (dc == null) {
-            return false;
-        }
 
         if (callback != null) {
+            final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+            if (dc == null) {
+                return false;
+            }
+
             WindowsForAccessibilityObserver observer =
                     mWindowsForAccessibilityObserver.get(displayId);
             if (isEmbeddedDisplay(dc)) {
@@ -209,21 +220,13 @@
                 if (Build.IS_DEBUGGABLE) {
                     throw new IllegalStateException(errorMessage);
                 }
-                removeObserverOfEmbeddedDisplay(observer);
+                removeObserversForEmbeddedChildDisplays(observer);
                 mWindowsForAccessibilityObserver.remove(displayId);
             }
             observer = new WindowsForAccessibilityObserver(mService, displayId, callback);
             mWindowsForAccessibilityObserver.put(displayId, observer);
             mAllObserversInitialized &= observer.mInitialized;
         } else {
-            if (isEmbeddedDisplay(dc)) {
-                // If this display is an embedded one, its window observer should be removed along
-                // with the window observer of its parent display removed because the window
-                // observer of the embedded display and its parent display is the same, and would
-                // be removed together when stopping the window tracking of its parent display. So
-                // here don't need to do removing window observer of the embedded display again.
-                return true;
-            }
             final WindowsForAccessibilityObserver windowsForA11yObserver =
                     mWindowsForAccessibilityObserver.get(displayId);
             if (windowsForA11yObserver == null) {
@@ -234,16 +237,17 @@
                     throw new IllegalStateException(errorMessage);
                 }
             }
-            removeObserverOfEmbeddedDisplay(windowsForA11yObserver);
+            removeObserversForEmbeddedChildDisplays(windowsForA11yObserver);
             mWindowsForAccessibilityObserver.remove(displayId);
         }
         return true;
     }
 
     void performComputeChangedWindowsNot(int displayId, boolean forceSend) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(
                     TAG + ".performComputeChangedWindowsNot",
+                    FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
                     "displayId=" + displayId + "; forceSend=" + forceSend);
         }
         WindowsForAccessibilityObserver observer = null;
@@ -260,8 +264,10 @@
     }
 
     void setMagnificationSpec(int displayId, MagnificationSpec spec) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".setMagnificationSpec",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
+                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".setMagnificationSpec",
+                    FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
                     "displayId=" + displayId + "; spec={" + spec + "}");
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
@@ -276,8 +282,9 @@
     }
 
     void getMagnificationRegion(int displayId, Region outMagnificationRegion) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".getMagnificationRegion",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".getMagnificationRegion",
+                    FLAGS_MAGNIFICATION_CALLBACK,
                     "displayId=" + displayId + "; outMagnificationRegion={" + outMagnificationRegion
                             + "}");
         }
@@ -288,9 +295,10 @@
     }
 
     void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(
                     TAG + ".onRectangleOnScreenRequested",
+                    FLAGS_MAGNIFICATION_CALLBACK,
                     "displayId=" + displayId + "; rectangle={" + rectangle + "}");
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
@@ -301,9 +309,11 @@
     }
 
     void onWindowLayersChanged(int displayId) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
-                    TAG + ".onWindowLayersChanged", "displayId=" + displayId);
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
+                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onWindowLayersChanged",
+                    FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
+                    "displayId=" + displayId);
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
         if (displayMagnifier != null) {
@@ -317,8 +327,10 @@
     }
 
     void onRotationChanged(DisplayContent displayContent) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".onRotationChanged",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
+                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onRotationChanged",
+                    FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
                     "displayContent={" + displayContent + "}");
         }
         final int displayId = displayContent.getDisplayId();
@@ -334,8 +346,9 @@
     }
 
     void onAppWindowTransition(int displayId, int transition) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".onAppWindowTransition",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onAppWindowTransition",
+                    FLAGS_MAGNIFICATION_CALLBACK,
                     "displayId=" + displayId + "; transition=" + transition);
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
@@ -346,8 +359,10 @@
     }
 
     void onWindowTransition(WindowState windowState, int transition) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".onWindowTransition",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
+                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onWindowTransition",
+                    FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
                     "windowState={" + windowState + "}; transition=" + transition);
         }
         final int displayId = windowState.getDisplayId();
@@ -364,9 +379,9 @@
 
     void onWindowFocusChangedNot(int displayId) {
         // Not relevant for the display magnifier.
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
-                    TAG + ".onWindowFocusChangedNot", "displayId=" + displayId);
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onWindowFocusChangedNot",
+                    FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "displayId=" + displayId);
         }
         WindowsForAccessibilityObserver observer = null;
         synchronized (mService.mGlobalLock) {
@@ -426,12 +441,10 @@
     }
 
     void onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
-                    TAG + ".onSomeWindowResizedOrMoved",
-                    "displayIds={" + displayIds.toString() + "}",
-                    "".getBytes(),
-                    callingUid);
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onSomeWindowResizedOrMoved",
+                    FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
+                    "displayIds={" + displayIds.toString() + "}", "".getBytes(), callingUid);
         }
         // Not relevant for the display magnifier.
         for (int i = 0; i < displayIds.length; i++) {
@@ -444,9 +457,10 @@
     }
 
     void drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(
                     TAG + ".drawMagnifiedRegionBorderIfNeeded",
+                    FLAGS_MAGNIFICATION_CALLBACK,
                     "displayId=" + displayId + "; transaction={" + t + "}");
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
@@ -457,8 +471,9 @@
     }
 
     MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".getMagnificationSpecForWindow",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForWindow",
+                    FLAGS_MAGNIFICATION_CALLBACK,
                     "windowState={" + windowState + "}");
         }
         final int displayId = windowState.getDisplayId();
@@ -470,17 +485,19 @@
     }
 
     boolean hasCallbacks() {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".hasCallbacks");
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
+                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".hasCallbacks",
+                    FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
         }
         return (mDisplayMagnifiers.size() > 0
                 || mWindowsForAccessibilityObserver.size() > 0);
     }
 
     void setForceShowMagnifiableBounds(int displayId, boolean show) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".setForceShowMagnifiableBounds",
-                    "displayId=" + displayId + "; show=" + show);
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".setForceShowMagnifiableBounds",
+                    FLAGS_MAGNIFICATION_CALLBACK, "displayId=" + displayId + "; show=" + show);
         }
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
         if (displayMagnifier != null) {
@@ -497,39 +514,50 @@
 
     void handleWindowObserverOfEmbeddedDisplay(
             int embeddedDisplayId, WindowState parentWindow, int callingUid) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".handleWindowObserverOfEmbeddedDisplay",
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".handleWindowObserverOfEmbeddedDisplay",
+                    FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
                     "embeddedDisplayId=" + embeddedDisplayId + "; parentWindowState={"
-                    + parentWindow + "}",
-                    "".getBytes(),
-                    callingUid);
+                    + parentWindow + "}", "".getBytes(), callingUid);
         }
         if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
             return;
         }
-        // Finds the parent display of this embedded display
-        final int parentDisplayId;
-        WindowState candidate = parentWindow;
-        while (candidate != null) {
-            parentWindow = candidate;
-            candidate = parentWindow.getDisplayContent().getParentWindow();
+        mService.mH.sendMessage(PooledLambda.obtainMessage(
+                AccessibilityController::updateWindowObserverOfEmbeddedDisplay,
+                this, embeddedDisplayId, parentWindow));
+    }
+
+    private void updateWindowObserverOfEmbeddedDisplay(int embeddedDisplayId,
+            WindowState parentWindow) {
+        final WindowsForAccessibilityObserver windowsForA11yObserver;
+
+        synchronized (mService.mGlobalLock) {
+            // Finds the parent display of this embedded display
+            WindowState candidate = parentWindow;
+            while (candidate != null) {
+                parentWindow = candidate;
+                candidate = parentWindow.getDisplayContent().getParentWindow();
+            }
+            final int parentDisplayId = parentWindow.getDisplayId();
+            // Uses the observer of parent display
+            windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId);
         }
-        parentDisplayId = parentWindow.getDisplayId();
-        // Uses the observer of parent display
-        final WindowsForAccessibilityObserver windowsForA11yObserver =
-                mWindowsForAccessibilityObserver.get(parentDisplayId);
 
         if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.notifyDisplayReparented(embeddedDisplayId);
             windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId);
-            // Replaces the observer of embedded display to the one of parent display
-            mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
+            synchronized (mService.mGlobalLock) {
+                // Replaces the observer of embedded display to the one of parent display
+                mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
+            }
         }
     }
 
     void onImeSurfaceShownChanged(WindowState windowState, boolean shown) {
-        if (mAccessibilityTracing.isEnabled()) {
-            mAccessibilityTracing.logState(TAG + ".onImeSurfaceShownChanged",
-                    "windowState=" + windowState + "; shown=" + shown);
+        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+            mAccessibilityTracing.logTrace(TAG + ".onImeSurfaceShownChanged",
+                    FLAGS_MAGNIFICATION_CALLBACK, "windowState=" + windowState + ";shown=" + shown);
         }
         final int displayId = windowState.getDisplayId();
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
@@ -555,7 +583,7 @@
                 + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver);
     }
 
-    private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver
+    private void removeObserversForEmbeddedChildDisplays(WindowsForAccessibilityObserver
             observerOfParentDisplay) {
         final IntArray embeddedDisplayIdList =
                 observerOfParentDisplay.getAndClearEmbeddedDisplayIdList();
@@ -599,7 +627,7 @@
         private final Handler mHandler;
         private final DisplayContent mDisplayContent;
         private final Display mDisplay;
-        private final AccessibilityTracing mAccessibilityTracing;
+        private final AccessibilityControllerInternalImpl mAccessibilityTracing;
 
         private final MagnificationCallbacks mCallbacks;
 
@@ -618,11 +646,13 @@
             mDisplay = display;
             mHandler = new MyHandler(mService.mH.getLooper());
             mMagnifedViewport = new MagnifiedViewport();
-            mAccessibilityTracing = AccessibilityTracing.getInstance(mService);
+            mAccessibilityTracing =
+                    AccessibilityController.getAccessibilityControllerInternal(mService);
             mLongAnimationDuration = mDisplayContext.getResources().getInteger(
                     com.android.internal.R.integer.config_longAnimTime);
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".DisplayMagnifier.constructor",
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".DisplayMagnifier.constructor",
+                        FLAGS_MAGNIFICATION_CALLBACK,
                         "windowManagerService={" + windowManagerService + "}; displayContent={"
                                 + displayContent + "}; display={" + display + "}; callbacks={"
                                 + callbacks + "}");
@@ -630,9 +660,9 @@
         }
 
         void setMagnificationSpec(MagnificationSpec spec) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(
-                        LOG_TAG + ".setMagnificationSpec", "spec={" + spec + "}");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".setMagnificationSpec",
+                        FLAGS_MAGNIFICATION_CALLBACK, "spec={" + spec + "}");
             }
             mMagnifedViewport.updateMagnificationSpec(spec);
             mMagnifedViewport.recomputeBounds();
@@ -642,25 +672,26 @@
         }
 
         void setForceShowMagnifiableBounds(boolean show) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(
-                        LOG_TAG + ".setForceShowMagnifiableBounds", "show=" + show);
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".setForceShowMagnifiableBounds",
+                        FLAGS_MAGNIFICATION_CALLBACK, "show=" + show);
             }
             mForceShowMagnifiableBounds = show;
             mMagnifedViewport.setMagnifiedRegionBorderShown(show, true);
         }
 
         boolean isForceShowingMagnifiableBounds() {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".isForceShowingMagnifiableBounds");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".isForceShowingMagnifiableBounds",
+                        FLAGS_MAGNIFICATION_CALLBACK);
             }
             return mForceShowMagnifiableBounds;
         }
 
         void onRectangleOnScreenRequested(Rect rectangle) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(
-                        LOG_TAG + ".onRectangleOnScreenRequested", "rectangle={" + rectangle + "}");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested",
+                        FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}");
             }
             if (DEBUG_RECTANGLE_REQUESTED) {
                 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
@@ -683,8 +714,9 @@
         }
 
         void onWindowLayersChanged() {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".onWindowLayersChanged");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(
+                        LOG_TAG + ".onWindowLayersChanged", FLAGS_MAGNIFICATION_CALLBACK);
             }
             if (DEBUG_LAYERS) {
                 Slog.i(LOG_TAG, "Layers changed.");
@@ -694,9 +726,9 @@
         }
 
         void onRotationChanged(DisplayContent displayContent) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(
-                        LOG_TAG + ".onRotationChanged", "displayContent={" + displayContent + "}");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".onRotationChanged",
+                        FLAGS_MAGNIFICATION_CALLBACK, "displayContent={" + displayContent + "}");
             }
             if (DEBUG_ROTATION) {
                 final int rotation = displayContent.getRotation();
@@ -708,8 +740,9 @@
         }
 
         void onAppWindowTransition(int displayId, int transition) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".onAppWindowTransition",
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".onAppWindowTransition",
+                        FLAGS_MAGNIFICATION_CALLBACK,
                         "displayId=" + displayId + "; transition=" + transition);
             }
             if (DEBUG_WINDOW_TRANSITIONS) {
@@ -733,8 +766,9 @@
         }
 
         void onWindowTransition(WindowState windowState, int transition) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".onWindowTransition",
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".onWindowTransition",
+                        FLAGS_MAGNIFICATION_CALLBACK,
                         "windowState={" + windowState + "}; transition=" + transition);
             }
             if (DEBUG_WINDOW_TRANSITIONS) {
@@ -791,18 +825,18 @@
         }
 
         void onImeSurfaceShownChanged(boolean shown) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(
-                        LOG_TAG + ".onImeSurfaceShownChanged", "shown=" + shown);
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".onImeSurfaceShownChanged",
+                        FLAGS_MAGNIFICATION_CALLBACK, "shown=" + shown);
             }
             mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED,
                     shown ? 1 : 0, 0).sendToTarget();
         }
 
         MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".getMagnificationSpecForWindow",
-                        "windowState={" + windowState + "}");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationSpecForWindow",
+                        FLAGS_MAGNIFICATION_CALLBACK, "windowState={" + windowState + "}");
             }
             MagnificationSpec spec = mMagnifedViewport.getMagnificationSpec();
             if (spec != null && !spec.isNop()) {
@@ -814,8 +848,9 @@
         }
 
         void getMagnificationRegion(Region outMagnificationRegion) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".getMagnificationRegion",
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".getMagnificationRegion",
+                        FLAGS_MAGNIFICATION_CALLBACK,
                         "outMagnificationRegion={" + outMagnificationRegion + "}");
             }
             // Make sure we're working with the most current bounds
@@ -824,25 +859,26 @@
         }
 
         void destroy() {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".destroy");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK);
             }
             mMagnifedViewport.destroyWindow();
         }
 
         // Can be called outside of a surface transaction
         void showMagnificationBoundsIfNeeded() {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".showMagnificationBoundsIfNeeded");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".showMagnificationBoundsIfNeeded",
+                        FLAGS_MAGNIFICATION_CALLBACK);
             }
             mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
                     .sendToTarget();
         }
 
         void drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
-                        "transition={" + t + "}");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
+                        FLAGS_MAGNIFICATION_CALLBACK, "transition={" + t + "}");
             }
             mMagnifedViewport.drawWindowIfNeeded(t);
         }
@@ -1482,7 +1518,7 @@
 
         private final Handler mHandler;
 
-        private final AccessibilityTracing mAccessibilityTracing;
+        private final AccessibilityControllerInternalImpl mAccessibilityTracing;
 
         private final WindowsForAccessibilityCallback mCallback;
 
@@ -1502,24 +1538,26 @@
             mCallback = callback;
             mDisplayId = displayId;
             mHandler = new MyHandler(mService.mH.getLooper());
-            mAccessibilityTracing = AccessibilityTracing.getInstance(mService);
+            mAccessibilityTracing =
+                    AccessibilityController.getAccessibilityControllerInternal(mService);
             mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
                     .getSendRecurringAccessibilityEventsInterval();
             computeChangedWindows(true);
         }
 
         void performComputeChangedWindows(boolean forceSend) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".performComputeChangedWindows",
-                        "forceSend=" + forceSend);
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".performComputeChangedWindows",
+                        FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "forceSend=" + forceSend);
             }
             mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
             computeChangedWindows(forceSend);
         }
 
         void scheduleComputeChangedWindows() {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(LOG_TAG + ".scheduleComputeChangedWindows");
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".scheduleComputeChangedWindows",
+                        FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
             }
             if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
                 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
@@ -1542,6 +1580,13 @@
             mEmbeddedDisplayIdList.add(displayId);
         }
 
+        void notifyDisplayReparented(int embeddedDisplayId) {
+            // Notifies the A11y framework the display is reparented and
+            // becomes an embedded display for removing the un-used
+            // displayWindowObserver of this embedded one.
+            mCallback.onDisplayReparented(embeddedDisplayId);
+        }
+
         boolean shellRootIsAbove(WindowState windowState, ShellRoot shellRoot) {
             int wsLayer = mService.mPolicy.getWindowLayerLw(windowState);
             int shellLayer = mService.mPolicy.getWindowLayerFromTypeLw(shellRoot.getWindowType(),
@@ -1594,9 +1639,9 @@
          * @param forceSend Send the windows the accessibility even if they haven't changed.
          */
         void computeChangedWindows(boolean forceSend) {
-            if (mAccessibilityTracing.isEnabled()) {
-                mAccessibilityTracing.logState(
-                        LOG_TAG + ".computeChangedWindows", "forceSend=" + forceSend);
+            if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
+                mAccessibilityTracing.logTrace(LOG_TAG + ".computeChangedWindows",
+                        FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, "forceSend=" + forceSend);
             }
             if (DEBUG) {
                 Slog.i(LOG_TAG, "computeChangedWindows()");
@@ -1945,8 +1990,8 @@
     private static final class AccessibilityControllerInternalImpl
             implements AccessibilityControllerInternal {
 
-        private static AccessibilityControllerInternal sInstance;
-        static AccessibilityControllerInternal getInstance(WindowManagerService service) {
+        private static AccessibilityControllerInternalImpl sInstance;
+        static AccessibilityControllerInternalImpl getInstance(WindowManagerService service) {
             synchronized (STATIC_LOCK) {
                 if (sInstance == null) {
                     sInstance = new AccessibilityControllerInternalImpl(service);
@@ -1956,18 +2001,23 @@
         }
 
         private final AccessibilityTracing mTracing;
+        private volatile long mEnabledTracingFlags;
+
         private AccessibilityControllerInternalImpl(WindowManagerService service) {
             mTracing = AccessibilityTracing.getInstance(service);
+            mEnabledTracingFlags = 0L;
         }
 
         @Override
-        public void startTrace() {
+        public void startTrace(long loggingTypes) {
+            mEnabledTracingFlags = loggingTypes;
             mTracing.startTrace();
         }
 
         @Override
         public void stopTrace() {
             mTracing.stopTrace();
+            mEnabledTracingFlags = 0L;
         }
 
         @Override
@@ -1975,19 +2025,37 @@
             return mTracing.isEnabled();
         }
 
-        @Override
-        public void logTrace(
-                String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] stackTrace) {
-            mTracing.logState(where, callingParams, a11yDump, callingUid, stackTrace);
+        boolean isTracingEnabled(long flags) {
+            return (flags & mEnabledTracingFlags) != 0L;
+        }
+
+        void logTrace(String where, long loggingTypes) {
+            logTrace(where, loggingTypes, "");
+        }
+
+        void logTrace(String where, long loggingTypes, String callingParams) {
+            logTrace(where, loggingTypes, callingParams, "".getBytes(), Binder.getCallingUid());
+        }
+
+        void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid) {
+            mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid,
+                    new HashSet<String>(Arrays.asList("logTrace")));
         }
 
         @Override
-        public void logTrace(
-                String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] callStack, long timeStamp, int processId, long threadId) {
-            mTracing.logState(where, callingParams, a11yDump, callingUid, callStack, timeStamp,
-                    processId, threadId);
+        public void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries) {
+            mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, stackTrace,
+                    ignoreStackEntries);
+        }
+
+        @Override
+        public void logTrace(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid, StackTraceElement[] callStack, long timeStamp, int processId,
+                long threadId, Set<String> ignoreStackEntries) {
+            mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, callStack,
+                    timeStamp, processId, threadId, ignoreStackEntries);
         }
     }
 
@@ -2004,7 +2072,6 @@
 
         private static final int BUFFER_CAPACITY = 1024 * 1024 * 12;
         private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace.pb";
-        private static final String TRACE_DIRECTORY = "/data/misc/a11ytrace/";
         private static final String TAG = "AccessibilityTracing";
         private static final long MAGIC_NUMBER_VALUE =
                 ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
@@ -2034,13 +2101,6 @@
                 return;
             }
             synchronized (mLock) {
-                try {
-                    Files.createDirectories(Paths.get(TRACE_DIRECTORY));
-                    mTraceFile.createNewFile();
-                } catch (Exception e) {
-                    Slog.e(TAG, "Error: Failed to create trace file.");
-                    return;
-                }
                 mEnabled = true;
                 mBuffer.resetBuffer();
             }
@@ -2071,86 +2131,127 @@
         /**
          * Write an accessibility trace log entry.
          */
-        void logState(String where) {
+        void logState(String where, long loggingTypes) {
             if (!mEnabled) {
                 return;
             }
-            logState(where, "");
+            logState(where, loggingTypes, "");
         }
 
         /**
          * Write an accessibility trace log entry.
          */
-        void logState(String where, String callingParams) {
+        void logState(String where, long loggingTypes, String callingParams) {
             if (!mEnabled) {
                 return;
             }
-            logState(where, callingParams, "".getBytes());
+            logState(where, loggingTypes, callingParams, "".getBytes());
         }
 
         /**
          * Write an accessibility trace log entry.
          */
-        void logState(String where, String callingParams, byte[] a11yDump) {
+        void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump) {
             if (!mEnabled) {
                 return;
             }
-            logState(where, callingParams, a11yDump, Binder.getCallingUid());
+            logState(where, loggingTypes, callingParams, a11yDump, Binder.getCallingUid(),
+                    new HashSet<String>(Arrays.asList("logState")));
         }
 
         /**
          * Write an accessibility trace log entry.
          */
-        void logState(
-                String where, String callingParams, byte[] a11yDump, int callingUid) {
+        void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid, Set<String> ignoreStackEntries) {
             if (!mEnabled) {
                 return;
             }
             StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
-
-            logState(where, callingParams, a11yDump, callingUid, stackTraceElements);
+            ignoreStackEntries.add("logState");
+            logState(where, loggingTypes, callingParams, a11yDump, callingUid, stackTraceElements,
+                    ignoreStackEntries);
         }
 
         /**
          * Write an accessibility trace log entry.
          */
-        void logState(String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] stackTrace) {
+        void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries) {
             if (!mEnabled) {
                 return;
             }
-
-            log(where, callingParams, a11yDump, callingUid, stackTrace,
+            log(where, loggingTypes, callingParams, a11yDump, callingUid, stackTrace,
                     SystemClock.elapsedRealtimeNanos(),
                     Process.myPid() + ":" + Application.getProcessName(),
-                    Thread.currentThread().getId() + ":" + Thread.currentThread().getName());
+                    Thread.currentThread().getId() + ":" + Thread.currentThread().getName(),
+                    ignoreStackEntries);
         }
 
         /**
          * Write an accessibility trace log entry.
          */
-        void logState(String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] callingStack, long timeStamp, int processId, long threadId) {
+        void logState(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid, StackTraceElement[] callingStack, long timeStamp, int processId,
+                long threadId, Set<String> ignoreStackEntries) {
             if (!mEnabled) {
                 return;
             }
-            log(where, callingParams, a11yDump, callingUid, callingStack, timeStamp,
-                    String.valueOf(processId), String.valueOf(threadId));
+            log(where, loggingTypes, callingParams, a11yDump, callingUid, callingStack, timeStamp,
+                    String.valueOf(processId), String.valueOf(threadId), ignoreStackEntries);
         }
 
-        private  String toStackTraceString(StackTraceElement[] stackTraceElements) {
+        private  String toStackTraceString(StackTraceElement[] stackTraceElements,
+                Set<String> ignoreStackEntries) {
+
             if (stackTraceElements == null) {
                 return "";
             }
+
             StringBuilder stringBuilder = new StringBuilder();
-            boolean skip = true;
-            for (int i = 0; i < stackTraceElements.length; i++) {
-                if (stackTraceElements[i].toString().contains(
-                            AccessibilityTracing.class.getSimpleName())) {
-                    skip = false;
-                } else if (!skip) {
-                    stringBuilder.append(stackTraceElements[i].toString()).append("\n");
+            int i = 0;
+
+            // Skip the first a few elements until after any ignoreStackEntries
+            int firstMatch = -1;
+            while (i < stackTraceElements.length) {
+                for (String ele : ignoreStackEntries) {
+                    if (stackTraceElements[i].toString().contains(ele)) {
+                        // found the first stack element containing the ignorable stack entries
+                        firstMatch = i;
+                        break;
+                    }
                 }
+                if (firstMatch < 0) {
+                    // Haven't found the first match yet, continue
+                    i++;
+                } else {
+                    break;
+                }
+            }
+            int lastMatch = firstMatch;
+            if (i < stackTraceElements.length) {
+                i++;
+                // Found the first match. Now look for the last match.
+                while (i < stackTraceElements.length) {
+                    for (String ele : ignoreStackEntries) {
+                        if (stackTraceElements[i].toString().contains(ele)) {
+                            // This is a match. Look at the next stack element.
+                            lastMatch = i;
+                            break;
+                        }
+                    }
+                    if (lastMatch != i) {
+                        // Found a no-match.
+                        break;
+                    }
+                    i++;
+                }
+            }
+
+            i = lastMatch + 1;
+            while (i < stackTraceElements.length) {
+                stringBuilder.append(stackTraceElements[i].toString()).append("\n");
+                i++;
             }
             return stringBuilder.toString();
         }
@@ -2158,19 +2259,22 @@
         /**
          * Write the current state to the buffer
          */
-        private void log(String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] callingStack, long timeStamp, String processName,
-                String threadName) {
+        private void log(String where, long loggingTypes, String callingParams, byte[] a11yDump,
+                int callingUid, StackTraceElement[] callingStack, long timeStamp,
+                String processName, String threadName, Set<String> ignoreStackEntries) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = timeStamp;
-            args.arg2 = where;
-            args.arg3 = processName;
-            args.arg4 = threadName;
-            args.arg5 = callingUid;
-            args.arg6 = callingParams;
-            args.arg7 = callingStack;
-            args.arg8 = a11yDump;
-            mHandler.obtainMessage(LogHandler.MESSAGE_LOG_TRACE_ENTRY, args).sendToTarget();
+            args.arg2 = loggingTypes;
+            args.arg3 = where;
+            args.arg4 = processName;
+            args.arg5 = threadName;
+            args.arg6 = ignoreStackEntries;
+            args.arg7 = callingParams;
+            args.arg8 = callingStack;
+            args.arg9 = a11yDump;
+
+            mHandler.obtainMessage(
+                    LogHandler.MESSAGE_LOG_TRACE_ENTRY, callingUid, 0, args).sendToTarget();
         }
 
         /**
@@ -2199,8 +2303,6 @@
                                     LocalServices.getService(PackageManagerInternal.class);
 
                             long tokenOuter = os.start(ENTRY);
-                            String callingStack =
-                                    toStackTraceString((StackTraceElement[]) args.arg7);
 
                             long reportedTimeStampNanos = (long) args.arg1;
                             long currentElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
@@ -2213,13 +2315,25 @@
 
                             os.write(ELAPSED_REALTIME_NANOS, reportedTimeStampNanos);
                             os.write(CALENDAR_TIME, fm.format(reportedTimeMillis).toString());
-                            os.write(WHERE, (String) args.arg2);
-                            os.write(PROCESS_NAME, (String) args.arg3);
-                            os.write(THREAD_ID_NAME, (String) args.arg4);
-                            os.write(CALLING_PKG, pmInternal.getNameForUid((int) args.arg5));
-                            os.write(CALLING_PARAMS, (String) args.arg6);
+
+                            long loggingTypes = (long) args.arg2;
+                            List<String> loggingTypeNames =
+                                    AccessibilityTrace.getNamesOfLoggingTypes(loggingTypes);
+
+                            for (String type : loggingTypeNames) {
+                                os.write(LOGGING_TYPE, type);
+                            }
+                            os.write(WHERE, (String) args.arg3);
+                            os.write(PROCESS_NAME, (String) args.arg4);
+                            os.write(THREAD_ID_NAME, (String) args.arg5);
+                            os.write(CALLING_PKG, pmInternal.getNameForUid(message.arg1));
+                            os.write(CALLING_PARAMS, (String) args.arg7);
+
+                            String callingStack = toStackTraceString(
+                                    (StackTraceElement[]) args.arg8, (Set<String>) args.arg6);
+
                             os.write(CALLING_STACKS, callingStack);
-                            os.write(ACCESSIBILITY_SERVICE, (byte[]) args.arg8);
+                            os.write(ACCESSIBILITY_SERVICE, (byte[]) args.arg9);
 
                             long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
                             synchronized (mService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 26f475e..a975ba6 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -28,6 +28,11 @@
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
+import static com.android.server.wm.ActivityRecord.State.DESTROYED;
+import static com.android.server.wm.ActivityRecord.State.DESTROYING;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -35,8 +40,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller;
-import static com.android.server.wm.Task.ActivityState.DESTROYED;
-import static com.android.server.wm.Task.ActivityState.DESTROYING;
 
 import android.annotation.NonNull;
 import android.app.Activity;
@@ -68,6 +71,7 @@
 import android.util.Slog;
 import android.view.RemoteAnimationDefinition;
 import android.window.SizeConfigurationBuckets;
+import android.window.TransitionInfo;
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -188,7 +192,7 @@
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped");
             r = ActivityRecord.isInRootTaskLocked(token);
             if (r != null) {
-                if (r.attachedToProcess() && r.isState(Task.ActivityState.RESTARTING_PROCESS)) {
+                if (r.attachedToProcess() && r.isState(RESTARTING_PROCESS)) {
                     // The activity was requested to restart from
                     // {@link #restartActivityProcessIfVisible}.
                     restartingName = r.app.mName;
@@ -1010,10 +1014,13 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
-            if (r != null && r.isState(Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) {
+            if (r != null && r.isState(RESUMED, PAUSING)) {
                 r.mDisplayContent.mAppTransition.overridePendingAppTransition(
                         packageName, enterAnim, exitAnim, null, null,
                         r.mOverrideTaskTransition);
+                mService.getTransitionController().setOverrideAnimation(
+                        TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName,
+                                enterAnim, exitAnim, r.mOverrideTaskTransition));
             }
         }
         Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 0f6a718..b2e3fcb 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -775,7 +775,7 @@
             Slog.i(TAG, "notifyVisibilityChanged " + r + " visible=" + r.mVisibleRequested
                     + " state=" + r.getState() + " finishing=" + r.finishing);
         }
-        if (r.isState(Task.ActivityState.RESUMED) && r.mDisplayContent.isSleeping()) {
+        if (r.isState(ActivityRecord.State.RESUMED) && r.mDisplayContent.isSleeping()) {
             // The activity may be launching while keyguard is locked. The keyguard may be dismissed
             // after the activity finished relayout, so skip the visibility check to avoid aborting
             // the tracking of launch event.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0ad8782..6140d77 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -129,6 +129,17 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityRecord.State.DESTROYED;
+import static com.android.server.wm.ActivityRecord.State.DESTROYING;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
+import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STARTED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN;
 import static com.android.server.wm.ActivityRecordProto.APP_STOPPED;
 import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE;
@@ -191,18 +202,7 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
-import static com.android.server.wm.Task.ActivityState.DESTROYED;
-import static com.android.server.wm.Task.ActivityState.DESTROYING;
-import static com.android.server.wm.Task.ActivityState.FINISHING;
-import static com.android.server.wm.Task.ActivityState.INITIALIZING;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.RESTARTING_PROCESS;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.ActivityState.STARTED;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
 import static com.android.server.wm.TaskPersister.DEBUG;
 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -301,6 +301,7 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
+import android.view.Surface.Rotation;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets.Type;
@@ -314,12 +315,14 @@
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
 import android.window.TaskSnapshot;
+import android.window.TransitionInfo.AnimationOptions;
 import android.window.WindowContainerToken;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.ReferrerIntent;
+import com.android.internal.os.TransferPipe;
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
@@ -336,7 +339,6 @@
 import com.android.server.uri.UriPermissionOwner;
 import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
-import com.android.server.wm.Task.ActivityState;
 import com.android.server.wm.WindowManagerService.H;
 import com.android.server.wm.utils.InsetUtils;
 
@@ -345,6 +347,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -488,7 +491,7 @@
     ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
     UriPermissionOwner uriPermissions; // current special URI access perms.
     WindowProcessController app;      // if non-null, hosting application
-    private ActivityState mState;    // current state we are in
+    private State mState;    // current state we are in
     private Bundle mIcicle;         // last saved activity state
     private PersistableBundle mPersistentState; // last persistently saved activity state
     private boolean mHaveState = true; // Indicates whether the last saved state of activity is
@@ -550,6 +553,21 @@
     static final int LAUNCH_SOURCE_TYPE_HOME = 2;
     static final int LAUNCH_SOURCE_TYPE_SYSTEMUI = 3;
     static final int LAUNCH_SOURCE_TYPE_APPLICATION = 4;
+
+    enum State {
+        INITIALIZING,
+        STARTED,
+        RESUMED,
+        PAUSING,
+        PAUSED,
+        STOPPING,
+        STOPPED,
+        FINISHING,
+        DESTROYING,
+        DESTROYED,
+        RESTARTING_PROCESS
+    }
+
     /**
      * The type of launch source.
      */
@@ -680,6 +698,8 @@
     private boolean mInSizeCompatModeForBounds = false;
 
     // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
+    // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration
+    // but that isn't reflected in this boolean.
     private boolean mIsAspectRatioApplied = false;
 
     // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
@@ -789,6 +809,7 @@
      */
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
+    private final Rect mTmpOutNonDecorBounds = new Rect();
 
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
@@ -1134,6 +1155,76 @@
         mLetterboxUiController.dump(pw, prefix);
     }
 
+    static boolean dumpActivity(FileDescriptor fd, PrintWriter pw, int index, ActivityRecord r,
+            String prefix, String label, boolean complete, boolean brief, boolean client,
+            String dumpPackage, boolean needNL, Runnable header, Task lastTask) {
+        if (dumpPackage != null && !dumpPackage.equals(r.packageName)) {
+            return false;
+        }
+
+        final boolean full = !brief && (complete || !r.isInHistory());
+        if (needNL) {
+            pw.println("");
+        }
+        if (header != null) {
+            header.run();
+        }
+
+        String innerPrefix = prefix + "      ";
+        String[] args = new String[0];
+        if (lastTask != r.getTask()) {
+            lastTask = r.getTask();
+            pw.print(prefix);
+            pw.print(full ? "* " : "  ");
+            pw.println(lastTask);
+            if (full) {
+                lastTask.dump(pw, prefix + "  ");
+            } else if (complete) {
+                // Complete + brief == give a summary.  Isn't that obvious?!?
+                if (lastTask.intent != null) {
+                    pw.print(prefix);
+                    pw.print("  ");
+                    pw.println(lastTask.intent.toInsecureString());
+                }
+            }
+        }
+        pw.print(prefix); pw.print(full ? "* " : "    "); pw.print(label);
+        pw.print(" #"); pw.print(index); pw.print(": ");
+        pw.println(r);
+        if (full) {
+            r.dump(pw, innerPrefix, true /* dumpAll */);
+        } else if (complete) {
+            // Complete + brief == give a summary.  Isn't that obvious?!?
+            pw.print(innerPrefix);
+            pw.println(r.intent.toInsecureString());
+            if (r.app != null) {
+                pw.print(innerPrefix);
+                pw.println(r.app);
+            }
+        }
+        if (client && r.attachedToProcess()) {
+            // flush anything that is already in the PrintWriter since the thread is going
+            // to write to the file descriptor directly
+            pw.flush();
+            try {
+                TransferPipe tp = new TransferPipe();
+                try {
+                    r.app.getThread().dumpActivity(
+                            tp.getWriteFd(), r.appToken, innerPrefix, args);
+                    // Short timeout, since blocking here can deadlock with the application.
+                    tp.go(fd, 2000);
+                } finally {
+                    tp.kill();
+                }
+            } catch (IOException e) {
+                pw.println(innerPrefix + "Failure while dumping the activity: " + e);
+            } catch (RemoteException e) {
+                pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
+            }
+        }
+        return true;
+    }
+
     void setAppTimeTracker(AppTimeTracker att) {
         appTimeTracker = att;
     }
@@ -1247,7 +1338,7 @@
                 // If the activity is in stopping or stopped state, for instance, it's in the
                 // split screen task and not the top one, the last configuration it should keep
                 // is the one before multi-window mode change.
-                final ActivityState state = getState();
+                final State state = getState();
                 if (state != STOPPED && state != STOPPING) {
                     ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
                             true /* ignoreVisibility */);
@@ -1280,21 +1371,30 @@
 
     private void computeConfigurationAfterMultiWindowModeChange() {
         final Configuration newConfig = new Configuration();
-        newConfig.setTo(task.getRequestedOverrideConfiguration());
+        final TaskFragment taskFrag = getTaskFragment();
+        newConfig.setTo(taskFrag.getRequestedOverrideConfiguration());
         Rect outBounds = newConfig.windowConfiguration.getBounds();
-        final Configuration parentConfig = task.getParent().getConfiguration();
-        task.adjustForMinimalTaskDimensions(outBounds, outBounds, parentConfig);
-        task.computeConfigResourceOverrides(newConfig, parentConfig);
+        // TODO(b/189384393): which parent does this Activity really needed?
+        // I guess we should either call getRootTask or getDisplayArea for this case.
+        final Configuration parentConfig = taskFrag.getParent().getConfiguration();
+        taskFrag.adjustForMinimalTaskDimensions(outBounds, outBounds, parentConfig);
+        taskFrag.computeConfigResourceOverrides(newConfig, parentConfig);
     }
 
     Task getTask() {
         return task;
     }
 
+    @Nullable
+    TaskFragment getTaskFragment() {
+        WindowContainer parent = getParent();
+        return parent != null ? parent.asTaskFragment() : null;
+    }
+
     @Override
     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final Task oldTask = oldParent != null ? (Task) oldParent : null;
-        final Task newTask = newParent != null ? (Task) newParent : null;
+        final Task oldTask = oldParent != null ? ((TaskFragment) oldParent).getTask() : null;
+        final Task newTask = newParent != null ? ((TaskFragment) newParent).getTask() : null;
         this.task = newTask;
 
         super.onParentChanged(newParent, oldParent);
@@ -1352,11 +1452,12 @@
 
         updateColorTransform();
 
-        if (oldTask != null) {
-            oldTask.cleanUpActivityReferences(this);
+        if (oldParent != null) {
+            ((TaskFragment) oldParent).cleanUpActivityReferences(this);
         }
-        if (newTask != null && isState(RESUMED)) {
-            newTask.setResumedActivity(this, "onParentChanged");
+
+        if (newParent != null && isState(RESUMED)) {
+            ((TaskFragment) newParent).setResumedActivity(this, "onParentChanged");
         }
 
         if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -2308,23 +2409,24 @@
     }
 
     /**
-     * Reparents this activity into {@param newTask} at the provided {@param position}.  The caller
-     * should ensure that the {@param newTask} is not already the parent of this activity.
+     * Reparents this activity into {@param newTaskFrag} at the provided {@param position}. The
+     * caller should ensure that the {@param newTaskFrag} is not already the parent of this
+     * activity.
      */
-    void reparent(Task newTask, int position, String reason) {
+    void reparent(TaskFragment newTaskFrag, int position, String reason) {
         if (getParent() == null) {
             Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken);
             return;
         }
-        final Task prevTask = task;
-        if (prevTask == newTask) {
-            throw new IllegalArgumentException(reason + ": task=" + newTask
+        final TaskFragment prevTaskFrag = getTaskFragment();
+        if (prevTaskFrag == newTaskFrag) {
+            throw new IllegalArgumentException(reason + ": task fragment =" + newTaskFrag
                     + " is already the parent of r=" + this);
         }
 
         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
-                + " to task=%d at %d", this, task.mTaskId, position);
-        reparent(newTask, position);
+                + " to new task fragment in task=%d at %d", this, task.mTaskId, position);
+        reparent(newTaskFrag, position);
     }
 
     private boolean isHomeIntent(Intent intent) {
@@ -2890,7 +2992,7 @@
         }
 
         final Task rootTask = getRootTask();
-        final boolean mayAdjustTop = (isState(RESUMED) || rootTask.getResumedActivity() == null)
+        final boolean mayAdjustTop = (isState(RESUMED) || rootTask.getTopResumedActivity() == null)
                 && rootTask.isFocusedRootTaskOnDisplay()
                 // Do not adjust focus task because the task will be reused to launch new activity.
                 && !task.isClearingToReuseTask();
@@ -2969,12 +3071,12 @@
                 // Tell window manager to prepare for this one to be removed.
                 setVisibility(false);
 
-                if (task.getPausingActivity() == null) {
+                if (getTaskFragment().getPausingActivity() == null) {
                     ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this);
                     if (DEBUG_USER_LEAVING) {
                         Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false");
                     }
-                    task.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+                    getTaskFragment().startPausing(false /* userLeaving */, false /* uiSleeping */,
                             null /* resuming */, "finish");
                 }
 
@@ -3293,8 +3395,8 @@
             if (DEBUG_SWITCH) {
                 final Task task = getTask();
                 Slog.v(TAG_SWITCH, "Safely destroying " + this + " in state " + getState()
-                        + " resumed=" + task.getResumedActivity()
-                        + " pausing=" + task.getPausingActivity()
+                        + " resumed=" + task.getTopResumedActivity()
+                        + " pausing=" + task.getTopPausingActivity()
                         + " for reason " + reason);
             }
             return destroyImmediately(reason);
@@ -3373,7 +3475,7 @@
      * Note: Call before {@link #removeFromHistory(String)}.
      */
     void cleanUp(boolean cleanServices, boolean setState) {
-        task.cleanUpActivityReferences(this);
+        getTaskFragment().cleanUpActivityReferences(this);
         clearLastParentBeforePip();
 
         // Clean up the splash screen if it was still displayed.
@@ -3481,7 +3583,7 @@
             // failed more than twice. Skip activities that's already finishing cleanly by itself.
             remove = false;
         } else if ((!mHaveState && !stateNotNeeded
-                && !isState(ActivityState.RESTARTING_PROCESS)) || finishing) {
+                && !isState(State.RESTARTING_PROCESS)) || finishing) {
             // Don't currently have state for the activity, or it is finishing -- always remove it.
             remove = true;
         } else if (!mVisibleRequested && launchCount > 2
@@ -4205,6 +4307,7 @@
     private void applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent) {
         final int animationType = pendingOptions.getAnimationType();
         final DisplayContent displayContent = getDisplayContent();
+        AnimationOptions options = null;
         switch (animationType) {
             case ANIM_CUSTOM:
                 displayContent.mAppTransition.overridePendingAppTransition(
@@ -4214,11 +4317,17 @@
                         pendingOptions.getAnimationStartedListener(),
                         pendingOptions.getAnimationFinishedListener(),
                         pendingOptions.getOverrideTaskTransition());
+                options = AnimationOptions.makeCustomAnimOptions(pendingOptions.getPackageName(),
+                        pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(),
+                        pendingOptions.getOverrideTaskTransition());
                 break;
             case ANIM_CLIP_REVEAL:
                 displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
                         pendingOptions.getStartX(), pendingOptions.getStartY(),
                         pendingOptions.getWidth(), pendingOptions.getHeight());
+                options = AnimationOptions.makeClipRevealAnimOptions(
+                        pendingOptions.getStartX(), pendingOptions.getStartY(),
+                        pendingOptions.getWidth(), pendingOptions.getHeight());
                 if (intent.getSourceBounds() == null) {
                     intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                             pendingOptions.getStartY(),
@@ -4230,6 +4339,9 @@
                 displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
                         pendingOptions.getStartX(), pendingOptions.getStartY(),
                         pendingOptions.getWidth(), pendingOptions.getHeight());
+                options = AnimationOptions.makeScaleUpAnimOptions(
+                        pendingOptions.getStartX(), pendingOptions.getStartY(),
+                        pendingOptions.getWidth(), pendingOptions.getHeight());
                 if (intent.getSourceBounds() == null) {
                     intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                             pendingOptions.getStartY(),
@@ -4245,6 +4357,8 @@
                         pendingOptions.getStartX(), pendingOptions.getStartY(),
                         pendingOptions.getAnimationStartedListener(),
                         scaleUp);
+                options = AnimationOptions.makeThumnbnailAnimOptions(buffer,
+                        pendingOptions.getStartX(), pendingOptions.getStartY(), scaleUp);
                 if (intent.getSourceBounds() == null && buffer != null) {
                     intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                             pendingOptions.getStartY(),
@@ -4284,6 +4398,7 @@
             case ANIM_OPEN_CROSS_PROFILE_APPS:
                 displayContent.mAppTransition
                         .overridePendingAppTransitionStartCrossProfileApps();
+                options = AnimationOptions.makeCrossProfileAnimOptions();
                 break;
             case ANIM_NONE:
             case ANIM_UNDEFINED:
@@ -4292,6 +4407,10 @@
                 Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
                 break;
         }
+
+        if (options != null) {
+            mAtmService.getTransitionController().setOverrideAnimation(options);
+        }
     }
 
     void clearAllDrawn() {
@@ -4424,6 +4543,10 @@
         }
     }
 
+    boolean getDeferHidingClient() {
+        return mDeferHidingClient;
+    }
+
     @Override
     boolean isVisible() {
         // If the activity isn't hidden then it is considered visible and there is no need to check
@@ -4588,7 +4711,7 @@
         }
 
         // If in a transition, defer commits for activities that are going invisible
-        if (!visible && mAtmService.getTransitionController().inTransition()) {
+        if (!visible && mAtmService.getTransitionController().inTransition(this)) {
             return;
         }
         // If we are preparing an app transition, then delay changing
@@ -4707,9 +4830,11 @@
      *                this has become invisible.
      */
     private void postApplyAnimation(boolean visible) {
+        final boolean usingShellTransitions =
+                mAtmService.getTransitionController().getTransitionPlayer() != null;
         final boolean delayed = isAnimating(PARENTS | CHILDREN,
                 ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION);
-        if (!delayed) {
+        if (!delayed && !usingShellTransitions) {
             // We aren't delayed anything, but exiting windows rely on the animation finished
             // callback being called in case the ActivityRecord was pretending to be delayed,
             // which we might have done because we were in closing/opening apps list.
@@ -4728,7 +4853,8 @@
         // updated.
         // If we're becoming invisible, update the client visibility if we are not running an
         // animation. Otherwise, we'll update client visibility in onAnimationFinished.
-        if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
+        if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)
+                || usingShellTransitions) {
             setClientVisible(visible);
         }
 
@@ -4837,7 +4963,7 @@
         return mCurrentLaunchCanTurnScreenOn;
     }
 
-    void setState(ActivityState state, String reason) {
+    void setState(State state, String reason) {
         ProtoLog.v(WM_DEBUG_STATES, "State movement: %s from:%s to:%s reason:%s",
                 this, getState(), state, reason);
 
@@ -4849,8 +4975,8 @@
 
         mState = state;
 
-        if (task != null) {
-            task.onActivityStateChanged(this, state, reason);
+        if (getTaskFragment() != null) {
+            getTaskFragment().onActivityStateChanged(this, state, reason);
         }
 
         // The WindowManager interprets the app stopping signal as
@@ -4910,44 +5036,42 @@
         }
     }
 
-    ActivityState getState() {
+    State getState() {
         return mState;
     }
 
     /**
      * Returns {@code true} if the Activity is in the specified state.
      */
-    boolean isState(ActivityState state) {
+    boolean isState(State state) {
         return state == mState;
     }
 
     /**
      * Returns {@code true} if the Activity is in one of the specified states.
      */
-    boolean isState(ActivityState state1, ActivityState state2) {
+    boolean isState(State state1, State state2) {
         return state1 == mState || state2 == mState;
     }
 
     /**
      * Returns {@code true} if the Activity is in one of the specified states.
      */
-    boolean isState(ActivityState state1, ActivityState state2, ActivityState state3) {
+    boolean isState(State state1, State state2, State state3) {
         return state1 == mState || state2 == mState || state3 == mState;
     }
 
     /**
      * Returns {@code true} if the Activity is in one of the specified states.
      */
-    boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
-            ActivityState state4) {
+    boolean isState(State state1, State state2, State state3, State state4) {
         return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
     }
 
     /**
      * Returns {@code true} if the Activity is in one of the specified states.
      */
-    boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
-            ActivityState state4, ActivityState state5) {
+    boolean isState(State state1, State state2, State state3, State state4, State state5) {
         return state1 == mState || state2 == mState || state3 == mState || state4 == mState
                 || state5 == mState;
     }
@@ -4955,8 +5079,8 @@
     /**
      * Returns {@code true} if the Activity is in one of the specified states.
      */
-    boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
-            ActivityState state4, ActivityState state5, ActivityState state6) {
+    boolean isState(State state1, State state2, State state3, State state4, State state5,
+            State state6) {
         return state1 == mState || state2 == mState || state3 == mState || state4 == mState
                 || state5 == mState || state6 == mState;
     }
@@ -5159,13 +5283,6 @@
                     supportsEnterPipOnTaskSwitch = false;
                     break;
                 case RESUMED:
-                    // If the app is capable of entering PIP, we should try pausing it now
-                    // so it can PIP correctly.
-                    if (deferHidingClient) {
-                        task.startPausingLocked(false /* uiSleeping */,
-                                null /* resuming */, "makeInvisible");
-                        break;
-                    }
                 case INITIALIZING:
                 case PAUSING:
                 case PAUSED:
@@ -5262,7 +5379,8 @@
      */
     private boolean shouldBeResumed(ActivityRecord activeActivity) {
         return shouldMakeActive(activeActivity) && isFocusable()
-                && getTask().getVisibility(activeActivity) == TASK_VISIBILITY_VISIBLE
+                && getTaskFragment().getVisibility(activeActivity)
+                        == TASK_FRAGMENT_VISIBILITY_VISIBLE
                 && canResumeByCompat();
     }
 
@@ -5316,7 +5434,7 @@
         if (!task.hasChild(this)) {
             throw new IllegalStateException("Activity not found in its task");
         }
-        return task.topRunningActivity() == this;
+        return getTaskFragment().topRunningActivity() == this;
     }
 
     void handleAlreadyVisible() {
@@ -5405,16 +5523,17 @@
         ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", appToken,
                 timeout);
 
-        if (task != null) {
+        final TaskFragment taskFragment = getTaskFragment();
+        if (taskFragment != null) {
             removePauseTimeout();
 
-            final ActivityRecord pausingActivity = task.getPausingActivity();
+            final ActivityRecord pausingActivity = taskFragment.getPausingActivity();
             if (pausingActivity == this) {
                 ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
                         (timeout ? "(due to timeout)" : " (pause complete)"));
                 mAtmService.deferWindowLayout();
                 try {
-                    task.completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
+                    taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);
                 } finally {
                     mAtmService.continueWindowLayout();
                 }
@@ -6077,9 +6196,9 @@
                 return this;
             }
             // Try to use the one which is closest to top.
-            ActivityRecord r = rootTask.getResumedActivity();
+            ActivityRecord r = rootTask.getTopResumedActivity();
             if (r == null) {
-                r = rootTask.getPausingActivity();
+                r = rootTask.getTopPausingActivity();
             }
             if (r != null) {
                 return r;
@@ -6157,7 +6276,8 @@
             // This would be redundant.
             return false;
         }
-        if (isState(RESUMED) || getRootTask() == null || this == task.getPausingActivity()
+        if (isState(RESUMED) || getRootTask() == null
+                || this == getTaskFragment().getPausingActivity()
                 || !mHaveState || !stopped) {
             // We're not ready for this kind of thing.
             return false;
@@ -6684,8 +6804,7 @@
         }
         final Configuration displayConfig = mDisplayContent.getConfiguration();
         return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
-                appRect, insets, thumbnailHeader, task, displayConfig.uiMode,
-                displayConfig.orientation);
+                appRect, insets, thumbnailHeader, task, displayConfig.orientation);
     }
 
     @Override
@@ -7110,7 +7229,8 @@
             // If the activity has requested override bounds, the configuration needs to be
             // computed accordingly.
             if (!matchParentBounds()) {
-                task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
+                getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
+                        newParentConfiguration);
             }
         // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
         // are already calculated in resolveFixedOrientationConfiguration.
@@ -7225,7 +7345,7 @@
         }
 
         // Since bounds has changed, the configuration needs to be computed accordingly.
-        task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
+        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
     }
 
     /**
@@ -7241,8 +7361,53 @@
     }
 
     /**
-     * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
-     * change and the requested orientation is different from the parent.
+     * In some cases, applying insets to bounds changes the orientation. For example, if a
+     * close-to-square display rotates to portrait to respect a portrait orientation activity, after
+     * insets such as the status and nav bars are applied, the activity may actually have a
+     * landscape orientation. This method checks whether the orientations of the activity window
+     * with and without insets match or if the orientation with insets already matches the
+     * requested orientation. If not, it may be necessary to letterbox the window.
+     * @param parentBounds are the new parent bounds passed down to the activity and should be used
+     *                     to compute the stable bounds.
+     * @param outBounds will store the stable bounds, which are the bounds with insets applied.
+     *                  These should be used to compute letterboxed bounds if orientation is not
+     *                  respected when insets are applied.
+     */
+    private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outBounds) {
+        if (mDisplayContent == null) {
+            return true;
+        }
+        // Only need to make changes if activity sets an orientation
+        final int requestedOrientation = getRequestedConfigurationOrientation();
+        if (requestedOrientation == ORIENTATION_UNDEFINED) {
+            return true;
+        }
+        // Compute parent orientation from bounds
+        final int orientation = parentBounds.height() >= parentBounds.width()
+                ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+        // Compute orientation from stable parent bounds (= parent bounds with insets applied)
+        final Task task = getTask();
+        task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
+                outBounds /* outStableBounds */, parentBounds /* bounds */,
+                mDisplayContent.getDisplayInfo());
+        final int orientationWithInsets = outBounds.height() >= outBounds.width()
+                ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+        // If orientation does not match the orientation with insets applied, then a
+        // display rotation will not be enough to respect orientation. However, even if they do
+        // not match but the orientation with insets applied matches the requested orientation, then
+        // there is no need to modify the bounds because when insets are applied, the activity will
+        // have the desired orientation.
+        return orientation == orientationWithInsets
+                || orientationWithInsets == requestedOrientation;
+    }
+
+    /**
+     * Computes bounds (letterbox or pillarbox) when either:
+     * 1. The parent doesn't handle the orientation change and the requested orientation is
+     *    different from the parent (see {@link DisplayContent#setIgnoreOrientationRequest()}.
+     * 2. The parent handling the orientation is not enough. This occurs when the display rotation
+     *    may not be enough to respect orientation requests (see {@link
+     *    ActivityRecord#orientationRespectedWithInsets}).
      *
      * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied
      * in this method.
@@ -7250,9 +7415,14 @@
     private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig,
             int windowingMode) {
         mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
-        if (handlesOrientationChangeFromDescendant()) {
+        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
+        final Rect containerBounds = new Rect(parentBounds);
+        boolean orientationRespectedWithInsets =
+                orientationRespectedWithInsets(parentBounds, containerBounds);
+        if (handlesOrientationChangeFromDescendant() && orientationRespectedWithInsets) {
             // No need to letterbox because of fixed orientation. Display will handle
-            // fixed-orientation requests.
+            // fixed-orientation requests and a display rotation is enough to respect requested
+            // orientation with insets applied.
             return;
         }
         if (WindowConfiguration.inMultiWindowMode(windowingMode) && isResizeable()) {
@@ -7272,7 +7442,8 @@
         // If the activity requires a different orientation (either by override or activityInfo),
         // make it fit the available bounds by scaling down its bounds.
         final int forcedOrientation = getRequestedConfigurationOrientation();
-        if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
+        if (forcedOrientation == ORIENTATION_UNDEFINED
+                || (forcedOrientation == parentOrientation && orientationRespectedWithInsets)) {
             return;
         }
 
@@ -7284,67 +7455,83 @@
             return;
         }
 
-        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
-        final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
-        final Rect containingBounds = new Rect();
-        final Rect containingAppBounds = new Rect();
-        // Need to shrink the containing bounds into a square because the parent orientation does
-        // not match the activity requested orientation.
-        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
-            // Shrink height to match width. Position height within app bounds.
-            final int bottom = Math.min(parentAppBounds.top + parentBounds.width(),
-                    parentAppBounds.bottom);
-            containingBounds.set(parentBounds.left, parentAppBounds.top, parentBounds.right,
-                    bottom);
-            containingAppBounds.set(parentAppBounds.left, parentAppBounds.top,
-                    parentAppBounds.right, bottom);
-        } else {
-            // Shrink width to match height. Position width within app bounds.
-            final int right = Math.min(parentAppBounds.left + parentBounds.height(),
-                    parentAppBounds.right);
-            containingBounds.set(parentAppBounds.left, parentBounds.top, right,
-                    parentBounds.bottom);
-            containingAppBounds.set(parentAppBounds.left, parentAppBounds.top, right,
-                    parentAppBounds.bottom);
-        }
-
-        Rect mTmpFullBounds = new Rect(resolvedBounds);
-        resolvedBounds.set(containingBounds);
+        // TODO(b/182268157) merge aspect ratio logic here and in
+        // {@link ActivityRecord#applyAspectRatio}
+        // if no aspect ratio constraints are provided, parent aspect ratio is used
+        float aspectRatio = computeAspectRatio(parentBounds);
 
         // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
         // set-fixed-orientation-letterbox-aspect-ratio.
         final float letterboxAspectRatioOverride =
                 mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
-        final float desiredAspectRatio =
-                letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
-                        ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
-        // Apply aspect ratio to resolved bounds
-        mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingAppBounds,
-                containingBounds, desiredAspectRatio, true);
+        aspectRatio = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+                ? letterboxAspectRatioOverride : aspectRatio;
 
-        // Vertically center if orientation is landscape. Bounds will later be horizontally centered
-        // in {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
+        // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
+        // order to use the extra available space.
+        final float maxAspectRatio = info.getMaxAspectRatio();
+        final float minAspectRatio = info.getMinAspectRatio();
+        if (aspectRatio > maxAspectRatio && maxAspectRatio != 0) {
+            aspectRatio = maxAspectRatio;
+        } else if (aspectRatio < minAspectRatio) {
+            aspectRatio = minAspectRatio;
+        }
+
+        // Store the current bounds to be able to revert to size compat mode values below if needed.
+        final Rect prevResolvedBounds = new Rect(resolvedBounds);
+
+        // Compute other dimension based on aspect ratio. Use bounds intersected with insets, stored
+        // in containerBounds after calling {@link ActivityRecord#orientationRespectedWithInsets()},
+        // to ensure that aspect ratio is respected after insets are applied.
+        int activityWidth;
+        int activityHeight;
         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
-            final int offsetY = parentBounds.centerY() - resolvedBounds.centerY();
-            resolvedBounds.offset(0, offsetY);
+            activityWidth = parentBounds.width();
+            // Compute height from stable bounds width to ensure orientation respected after insets.
+            activityHeight = (int) Math.rint(containerBounds.width() / aspectRatio);
+            // Landscape is defined as width > height. To ensure activity is landscape when aspect
+            // ratio is close to 1, reduce the height by one pixel.
+            if (activityWidth == activityHeight) {
+                activityHeight -= 1;
+            }
+            // Center vertically within stable bounds in landscape to ensure insets do not trim
+            // height.
+            final int top = containerBounds.centerY() - activityHeight / 2;
+            resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + activityHeight);
+        } else {
+            activityHeight = parentBounds.height();
+            // Compute width from stable bounds height to ensure orientation respected after insets.
+            activityWidth = (int) Math.rint(containerBounds.height() / aspectRatio);
+            // Center horizontally in portrait. For now, align to left and allow
+            // {@link ActivityRecord#updateResolvedBoundsHorizontalPosition()} to center
+            // horizontally. Exclude left insets from parent to ensure cutout does not trim width.
+            final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+            resolvedBounds.set(parentAppBounds.left, parentBounds.top,
+                    parentAppBounds.left + activityWidth, parentBounds.bottom);
         }
 
         if (mCompatDisplayInsets != null) {
             mCompatDisplayInsets.getBoundsByRotation(
                     mTmpBounds, newParentConfig.windowConfiguration.getRotation());
-            if (resolvedBounds.width() != mTmpBounds.width()
-                    || resolvedBounds.height() != mTmpBounds.height()) {
+            // Insets may differ between different rotations, for example in the case of a display
+            // cutout. To ensure consistent bounds across rotations, compare the activity dimensions
+            // minus insets from the rotation the compat bounds were computed in.
+            Task.intersectWithInsetsIfFits(mTmpBounds, parentBounds,
+                    mCompatDisplayInsets.mStableInsets[mCompatDisplayInsets.mOriginalRotation]);
+            if (activityWidth != mTmpBounds.width()
+                    || activityHeight != mTmpBounds.height()) {
                 // The app shouldn't be resized, we only do fixed orientation letterboxing if the
                 // compat bounds are also from the same fixed orientation letterbox. Otherwise,
                 // clear the fixed orientation bounds to show app in size compat mode.
-                resolvedBounds.set(mTmpFullBounds);
+                resolvedBounds.set(prevResolvedBounds);
                 return;
             }
         }
 
         // Calculate app bounds using fixed orientation bounds because they will be needed later
         // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
-        task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+        getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
+                newParentConfig);
         mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
     }
 
@@ -7368,11 +7555,13 @@
         // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
         if (!mTmpBounds.isEmpty()) {
             resolvedBounds.set(mTmpBounds);
+            // Exclude the horizontal decor area.
+            resolvedBounds.left = parentAppBounds.left;
         }
         if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
             // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
             // restrict, the bounds should be the requested override bounds.
-            task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+            getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                     getFixedRotationTransformDisplayInfo());
         }
     }
@@ -7428,14 +7617,21 @@
             mIsAspectRatioApplied =
                     applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
         }
+        // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
+        // the container app bounds. Otherwise the entire container bounds are available.
+        final boolean fillContainer = resolvedBounds.equals(containingBounds);
+        if (!fillContainer) {
+            // The horizontal position should not cover insets.
+            resolvedBounds.left = containingAppBounds.left;
+        }
 
         // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
         // are calculated in compat container space. The actual position on screen will be applied
         // later, so the calculation is simpler that doesn't need to involve offset from parent.
-        task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+        getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                 mCompatDisplayInsets);
         // Use current screen layout as source because the size of app is independent to parent.
-        resolvedConfig.screenLayout = Task.computeScreenLayoutOverride(
+        resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
                 getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
                 resolvedConfig.screenHeightDp);
 
@@ -7494,7 +7690,6 @@
         // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
         // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
         // Above coordinates are in "@" space, now place "*" and "#" to screen space.
-        final boolean fillContainer = resolvedBounds.equals(containingBounds);
         final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
         final int screenPosY = containerBounds.top;
         if (screenPosX != 0 || screenPosY != 0) {
@@ -7579,6 +7774,10 @@
         if (getUid() == SYSTEM_UID) {
             return false;
         }
+        // Do not sandbox to activity window bounds if the feature is disabled.
+        if (mDisplayContent != null && !mDisplayContent.sandboxDisplayApis()) {
+            return false;
+        }
         // Never apply sandboxing to an app that should be explicitly excluded from the config.
         if (info != null && info.neverSandboxDisplayApis()) {
             return false;
@@ -7731,12 +7930,6 @@
         return true;
     }
 
-    private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
-            Rect containingBounds) {
-        return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
-                0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
-    }
-
     /**
      * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
      * made to outBounds.
@@ -7745,19 +7938,17 @@
      */
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
     private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
-            Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
+            Rect containingBounds) {
         final float maxAspectRatio = info.getMaxAspectRatio();
         final Task rootTask = getRootTask();
         final float minAspectRatio = info.getMinAspectRatio();
 
         if (task == null || rootTask == null
-                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()
-                    && !fixedOrientationLetterboxed)
-                || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
+                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
+                || (maxAspectRatio == 0 && minAspectRatio == 0)
                 || isInVrUiMode(getConfiguration())) {
-            // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
-            // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
-            // are in VR mode.
+            // We don't enforce aspect ratio if the activity task is in multiwindow unless it
+            // is in size-compat mode. We also don't set it if we are in VR mode.
             return false;
         }
 
@@ -7765,30 +7956,20 @@
         final int containingAppHeight = containingAppBounds.height();
         final float containingRatio = computeAspectRatio(containingAppBounds);
 
-        if (desiredAspectRatio < 1) {
-            desiredAspectRatio = containingRatio;
-        }
-
-        if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
-            desiredAspectRatio = maxAspectRatio;
-        } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
-            desiredAspectRatio = minAspectRatio;
-        }
-
         int activityWidth = containingAppWidth;
         int activityHeight = containingAppHeight;
 
-        if (containingRatio > desiredAspectRatio) {
+        if (containingRatio > maxAspectRatio && maxAspectRatio != 0) {
             if (containingAppWidth < containingAppHeight) {
                 // Width is the shorter side, so we use that to figure-out what the max. height
                 // should be given the aspect ratio.
-                activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
+                activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f);
             } else {
                 // Height is the shorter side, so we use that to figure-out what the max. width
                 // should be given the aspect ratio.
-                activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
+                activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
             }
-        } else if (containingRatio < desiredAspectRatio) {
+        } else if (containingRatio < minAspectRatio) {
             boolean adjustWidth;
             switch (getRequestedConfigurationOrientation()) {
                 case ORIENTATION_LANDSCAPE:
@@ -7816,9 +7997,9 @@
                     break;
             }
             if (adjustWidth) {
-                activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
+                activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
             } else {
-                activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
+                activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
             }
         }
 
@@ -7842,13 +8023,6 @@
         }
         outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
 
-        // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
-        // container app bounds. Otherwise the entire container bounds are available.
-        if (!outBounds.equals(containingBounds)) {
-            // The horizontal position should not cover insets.
-            outBounds.left = containingAppBounds.left;
-        }
-
         return true;
     }
 
@@ -8604,6 +8778,8 @@
      * compatibility mode activity compute the configuration without relying on its current display.
      */
     static class CompatDisplayInsets {
+        /** The original rotation the compat insets were computed in */
+        final @Rotation int mOriginalRotation;
         /** The container width on rotation 0. */
         private final int mWidth;
         /** The container height on rotation 0. */
@@ -8630,6 +8806,7 @@
         /** Constructs the environment to simulate the bounds behavior of the given container. */
         CompatDisplayInsets(DisplayContent display, ActivityRecord container,
                 @Nullable Rect fixedOrientationBounds) {
+            mOriginalRotation = display.getRotation();
             mIsFloating = container.getWindowConfiguration().tasksAreFloating();
             if (mIsFloating) {
                 final Rect containerBounds = container.getWindowConfiguration().getBounds();
@@ -8776,7 +8953,8 @@
                 outAppBounds.offset(insets.left, insets.top);
             } else if (rotation != ROTATION_UNDEFINED) {
                 // Ensure the app bounds won't overlap with insets.
-                Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]);
+                TaskFragment.intersectWithInsetsIfFits(outAppBounds, outBounds,
+                        mNonDecorInsets[rotation]);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
index 8540fa7..30c7b23 100644
--- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
+++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
@@ -16,10 +16,10 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
 
 import android.util.ArraySet;
 import android.util.Slog;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e2ef82b..8b09ba9 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -28,6 +28,7 @@
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -58,6 +59,7 @@
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
@@ -74,7 +76,6 @@
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
 import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -1549,6 +1550,11 @@
             newTransition.setRemoteTransition(remoteTransition);
         }
         mService.getTransitionController().collect(r);
+        // TODO(b/188669821): Remove when navbar reparenting moves to shell
+        if (r.getActivityType() == ACTIVITY_TYPE_HOME && r.getOptions() != null
+                && r.getOptions().getTransientLaunch()) {
+            mService.getTransitionController().setIsLegacyRecents();
+        }
         try {
             mService.deferWindowLayout();
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
@@ -1580,7 +1586,8 @@
                         statusBar.collapsePanels();
                     }
                 }
-                if (result == START_SUCCESS || result == START_TASK_TO_FRONT) {
+                final boolean started = result == START_SUCCESS || result == START_TASK_TO_FRONT;
+                if (started) {
                     // The activity is started new rather than just brought forward, so record
                     // it as an existence change.
                     mService.getTransitionController().collectExistenceChange(r);
@@ -1588,7 +1595,7 @@
                 if (newTransition != null) {
                     mService.getTransitionController().requestStartTransition(newTransition,
                             mTargetTask, remoteTransition);
-                } else {
+                } else if (started) {
                     // Make the collecting transition wait until this request is ready.
                     mService.getTransitionController().setReady(false);
                 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 569c11b..4045e87 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1216,8 +1216,8 @@
             // If this is coming from the currently resumed activity, it is
             // effectively saying that app switches are allowed at this point.
             final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
-            if (topFocusedRootTask != null && topFocusedRootTask.getResumedActivity() != null
-                    && topFocusedRootTask.getResumedActivity().info.applicationInfo.uid
+            if (topFocusedRootTask != null && topFocusedRootTask.getTopResumedActivity() != null
+                    && topFocusedRootTask.getTopResumedActivity().info.applicationInfo.uid
                     == Binder.getCallingUid()) {
                 mAppSwitchesAllowed = true;
             }
@@ -3739,6 +3739,20 @@
         }
     }
 
+    @Override
+    public void detachNavigationBarFromApp(@NonNull IBinder transition) {
+        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+                "detachNavigationBarFromApp");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                getTransitionController().legacyDetachNavigationBarFromApp(transition);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     void dumpLastANRLocked(PrintWriter pw) {
         pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
         if (mLastANRState == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index d3d1c1c..08bca35 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -48,6 +48,9 @@
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
@@ -72,8 +75,6 @@
 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
 import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
 import static com.android.server.wm.Task.TAG_CLEANUP;
@@ -136,7 +137,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
-import com.android.internal.os.TransferPipe;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.function.pooled.PooledConsumer;
@@ -146,7 +146,6 @@
 import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
 
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -1968,76 +1967,14 @@
     static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
             String prefix, String label, boolean complete, boolean brief, boolean client,
             String dumpPackage, boolean needNL, Runnable header, Task lastTask) {
-        String innerPrefix = null;
-        String[] args = null;
         boolean printed = false;
-        for (int i=list.size()-1; i>=0; i--) {
+        for (int i = list.size() - 1; i >= 0; i--) {
             final ActivityRecord r = list.get(i);
-            if (dumpPackage != null && !dumpPackage.equals(r.packageName)) {
-                continue;
-            }
-            if (innerPrefix == null) {
-                innerPrefix = prefix + "      ";
-                args = new String[0];
-            }
-            printed = true;
-            final boolean full = !brief && (complete || !r.isInHistory());
-            if (needNL) {
-                pw.println("");
-                needNL = false;
-            }
-            if (header != null) {
-                header.run();
-                header = null;
-            }
-            if (lastTask != r.getTask()) {
-                lastTask = r.getTask();
-                pw.print(prefix);
-                pw.print(full ? "* " : "  ");
-                pw.println(lastTask);
-                if (full) {
-                    lastTask.dump(pw, prefix + "  ");
-                } else if (complete) {
-                    // Complete + brief == give a summary.  Isn't that obvious?!?
-                    if (lastTask.intent != null) {
-                        pw.print(prefix); pw.print("  ");
-                                pw.println(lastTask.intent.toInsecureString());
-                    }
-                }
-            }
-            pw.print(prefix); pw.print(full ? "  * " : "    "); pw.print(label);
-            pw.print(" #"); pw.print(i); pw.print(": ");
-            pw.println(r);
-            if (full) {
-                r.dump(pw, innerPrefix, true /* dumpAll */);
-            } else if (complete) {
-                // Complete + brief == give a summary.  Isn't that obvious?!?
-                pw.print(innerPrefix); pw.println(r.intent.toInsecureString());
-                if (r.app != null) {
-                    pw.print(innerPrefix); pw.println(r.app);
-                }
-            }
-            if (client && r.attachedToProcess()) {
-                // flush anything that is already in the PrintWriter since the thread is going
-                // to write to the file descriptor directly
-                pw.flush();
-                try {
-                    TransferPipe tp = new TransferPipe();
-                    try {
-                        r.app.getThread().dumpActivity(
-                                tp.getWriteFd(), r.appToken, innerPrefix, args);
-                        // Short timeout, since blocking here can deadlock with the application.
-                        tp.go(fd, 2000);
-                    } finally {
-                        tp.kill();
-                    }
-                } catch (IOException e) {
-                    pw.println(innerPrefix + "Failure while dumping the activity: " + e);
-                } catch (RemoteException e) {
-                    pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
-                }
-                needNL = true;
-            }
+            ActivityRecord.dumpActivity(fd, pw, i, r, prefix, label, complete, brief,
+                    client, dumpPackage, needNL, header, lastTask);
+            lastTask = r.getTask();
+            header = null;
+            needNL = client && r.attachedToProcess();
         }
         return printed;
     }
@@ -2064,7 +2001,7 @@
     void updateTopResumedActivityIfNeeded() {
         final ActivityRecord prevTopActivity = mTopResumedActivity;
         final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
-        if (topRootTask == null || topRootTask.getResumedActivity() == prevTopActivity) {
+        if (topRootTask == null || topRootTask.getTopResumedActivity() == prevTopActivity) {
             if (mService.isSleepingLocked()) {
                 // There won't be a next resumed activity. The top process should still be updated
                 // according to the current top focused activity.
@@ -2086,7 +2023,7 @@
         }
 
         // Update the current top activity.
-        mTopResumedActivity = topRootTask.getResumedActivity();
+        mTopResumedActivity = topRootTask.getTopResumedActivity();
         scheduleTopResumedActivityStateIfNeeded();
 
         mService.updateTopApp(mTopResumedActivity);
@@ -2393,8 +2330,7 @@
                     String processName = null;
                     int uid = 0;
                     synchronized (mService.mGlobalLock) {
-                        if (r.attachedToProcess()
-                                && r.isState(Task.ActivityState.RESTARTING_PROCESS)) {
+                        if (r.attachedToProcess() && r.isState(RESTARTING_PROCESS)) {
                             processName = r.app.mName;
                             uid = r.app.mUid;
                         }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c1b287f..ac687dc 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -78,10 +78,7 @@
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
-import static com.android.internal.policy.TransitionAnimation.THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
-import static com.android.internal.policy.TransitionAnimation.THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
-import static com.android.internal.policy.TransitionAnimation.THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
-import static com.android.internal.policy.TransitionAnimation.THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
+import static com.android.internal.policy.TransitionAnimation.prepareThumbnailAnimationWithDuration;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
@@ -102,12 +99,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Picture;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.hardware.HardwareBuffer;
 import android.os.Binder;
 import android.os.Debug;
@@ -132,7 +124,6 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
-import android.view.animation.ClipRectAnimation;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 import android.view.animation.ScaleAnimation;
@@ -641,24 +632,6 @@
     /**
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
-    Animation prepareThumbnailAnimationWithDuration(@Nullable Animation a, int appWidth,
-            int appHeight, long duration, Interpolator interpolator) {
-        if (a != null) {
-            if (duration > 0) {
-                a.setDuration(duration);
-            }
-            a.setFillAfter(true);
-            if (interpolator != null) {
-                a.setInterpolator(interpolator);
-            }
-            a.initialize(appWidth, appHeight, appWidth, appHeight);
-        }
-        return a;
-    }
-
-    /**
-     * Prepares the specified animation with a standard duration, interpolator, etc.
-     */
     Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
         // Pick the desired duration.  If this is an inter-activity transition,
         // it  is the standard duration for that.  Otherwise we use the longer
@@ -678,56 +651,16 @@
     }
 
     /**
-     * Return the current thumbnail transition state.
-     */
-    int getThumbnailTransitionState(boolean enter) {
-        if (enter) {
-            if (mNextAppTransitionScaleUp) {
-                return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
-            } else {
-                return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
-            }
-        } else {
-            if (mNextAppTransitionScaleUp) {
-                return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
-            } else {
-                return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
-            }
-        }
-    }
-
-    /**
      * Creates an overlay with a background color and a thumbnail for the cross profile apps
      * animation.
      */
     HardwareBuffer createCrossProfileAppsThumbnail(
             @DrawableRes int thumbnailDrawableRes, Rect frame) {
-        final int width = frame.width();
-        final int height = frame.height();
-
-        final Picture picture = new Picture();
-        final Canvas canvas = picture.beginRecording(width, height);
-        canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
-        final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
-        final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes);
-        drawable.setBounds(
-                (width - thumbnailSize) / 2,
-                (height - thumbnailSize) / 2,
-                (width + thumbnailSize) / 2,
-                (height + thumbnailSize) / 2);
-        drawable.setTint(mContext.getColor(android.R.color.white));
-        drawable.draw(canvas);
-        picture.endRecording();
-
-        return Bitmap.createBitmap(picture).getHardwareBuffer();
+        return mTransitionAnimation.createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
     }
 
     Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
-        final Animation animation =
-                mTransitionAnimation.loadCrossProfileAppThumbnailEnterAnimation();
-        return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
-                appRect.height(), 0, null);
+        return mTransitionAnimation.createCrossProfileAppsThumbnailAnimationLocked(appRect);
     }
 
     /**
@@ -735,115 +668,14 @@
      * when a thumbnail is specified with the pending animation override.
      */
     Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
-            HardwareBuffer thumbnailHeader, WindowContainer container, int uiMode,
-            int orientation) {
-        Animation a;
-        final int thumbWidthI = thumbnailHeader.getWidth();
-        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
-        final int thumbHeightI = thumbnailHeader.getHeight();
-        final int appWidth = appRect.width();
-
-        float scaleW = appWidth / thumbWidth;
-        getNextAppTransitionStartRect(container, mTmpRect);
-        final float fromX;
-        float fromY;
-        final float toX;
-        float toY;
-        final float pivotX;
-        final float pivotY;
-        if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
-            fromX = mTmpRect.left;
-            fromY = mTmpRect.top;
-
-            // For the curved translate animation to work, the pivot points needs to be at the
-            // same absolute position as the one from the real surface.
-            toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
-            toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
-            pivotX = mTmpRect.width() / 2;
-            pivotY = appRect.height() / 2 / scaleW;
-            if (mGridLayoutRecentsEnabled) {
-                // In the grid layout, the header is displayed above the thumbnail instead of
-                // overlapping it.
-                fromY -= thumbHeightI;
-                toY -= thumbHeightI * scaleW;
-            }
-        } else {
-            pivotX = 0;
-            pivotY = 0;
-            fromX = mTmpRect.left;
-            fromY = mTmpRect.top;
-            toX = appRect.left;
-            toY = appRect.top;
-        }
-        final long duration = getAspectScaleDuration();
-        final Interpolator interpolator = getAspectScaleInterpolator();
-        if (mNextAppTransitionScaleUp) {
-            // Animation up from the thumbnail to the full screen
-            Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
-            scale.setInterpolator(interpolator);
-            scale.setDuration(duration);
-            Animation alpha = new AlphaAnimation(1f, 0f);
-            alpha.setInterpolator(mThumbnailFadeOutInterpolator);
-            alpha.setDuration(duration);
-            Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
-            translate.setInterpolator(interpolator);
-            translate.setDuration(duration);
-
-            mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
-            mTmpToClipRect.set(appRect);
-
-            // Containing frame is in screen space, but we need the clip rect in the
-            // app space.
-            mTmpToClipRect.offsetTo(0, 0);
-            mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
-            mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
-
-            if (contentInsets != null) {
-                mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
-                        (int) (-contentInsets.top * scaleW),
-                        (int) (-contentInsets.right * scaleW),
-                        (int) (-contentInsets.bottom * scaleW));
-            }
-
-            Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-            clipAnim.setInterpolator(interpolator);
-            clipAnim.setDuration(duration);
-
-            // This AnimationSet uses the Interpolators assigned above.
-            AnimationSet set = new AnimationSet(false);
-            set.addAnimation(scale);
-            if (!mGridLayoutRecentsEnabled) {
-                // In the grid layout, the header should be shown for the whole animation.
-                set.addAnimation(alpha);
-            }
-            set.addAnimation(translate);
-            set.addAnimation(clipAnim);
-            a = set;
-        } else {
-            // Animation down from the full screen to the thumbnail
-            Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
-            scale.setInterpolator(interpolator);
-            scale.setDuration(duration);
-            Animation alpha = new AlphaAnimation(0f, 1f);
-            alpha.setInterpolator(mThumbnailFadeInInterpolator);
-            alpha.setDuration(duration);
-            Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
-            translate.setInterpolator(interpolator);
-            translate.setDuration(duration);
-
-            // This AnimationSet uses the Interpolators assigned above.
-            AnimationSet set = new AnimationSet(false);
-            set.addAnimation(scale);
-            if (!mGridLayoutRecentsEnabled) {
-                // In the grid layout, the header should be shown for the whole animation.
-                set.addAnimation(alpha);
-            }
-            set.addAnimation(translate);
-            a = set;
-
-        }
-        return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
-                null);
+            HardwareBuffer thumbnailHeader, WindowContainer container, int orientation) {
+        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
+                container.hashCode());
+        return mTransitionAnimation.createThumbnailAspectScaleAnimationLocked(appRect,
+                contentInsets, thumbnailHeader, orientation, spec != null ? spec.rect : null,
+                mDefaultNextAppTransitionAnimationSpec != null
+                        ? mDefaultNextAppTransitionAnimationSpec.rect : null,
+                mNextAppTransitionScaleUp);
     }
 
     private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
@@ -1043,7 +875,7 @@
                             + "transit=%s Callers=%s",
                     a, appTransitionOldToString(transit), Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
-            a = mTransitionAnimation.createClipRevealAnimationLocked(
+            a = mTransitionAnimation.createClipRevealAnimationLockedCompat(
                     transit, enter, frame, displayFrame,
                     mDefaultNextAppTransitionAnimationSpec != null
                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);
@@ -1052,7 +884,7 @@
                             + "transit=%s Callers=%s",
                     a, appTransitionOldToString(transit), Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
-            a = mTransitionAnimation.createScaleUpAnimationLocked(transit, enter, frame,
+            a = mTransitionAnimation.createScaleUpAnimationLockedCompat(transit, enter, frame,
                     mDefaultNextAppTransitionAnimationSpec != null
                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
@@ -1064,8 +896,8 @@
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
             final HardwareBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);
-            a = mTransitionAnimation.createThumbnailEnterExitAnimationLocked(
-                    getThumbnailTransitionState(enter), frame, transit, thumbnailHeader,
+            a = mTransitionAnimation.createThumbnailEnterExitAnimationLockedCompat(enter,
+                    mNextAppTransitionScaleUp, frame, transit, thumbnailHeader,
                     mDefaultNextAppTransitionAnimationSpec != null
                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
@@ -1080,9 +912,9 @@
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
             AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
                     container.hashCode());
-            a = mTransitionAnimation.createAspectScaledThumbnailEnterExitAnimationLocked(
-                    getThumbnailTransitionState(enter), orientation, transit, frame,
-                    insets, surfaceInsets, stableInsets, freeform, spec != null ? spec.rect : null,
+            a = mTransitionAnimation.createAspectScaledThumbnailEnterExitAnimationLocked(enter,
+                    mNextAppTransitionScaleUp, orientation, transit, frame, insets, surfaceInsets,
+                    stableInsets, freeform, spec != null ? spec.rect : null,
                     mDefaultNextAppTransitionAnimationSpec != null
                             ? mDefaultNextAppTransitionAnimationSpec.rect : null);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 8fbe177..2eeabf2 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -34,6 +34,7 @@
 import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
 
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
 import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -111,6 +112,7 @@
      * This method should be used for getting settings applied in each particular level of the
      * hierarchy.
      */
+    @NonNull
     public Configuration getConfiguration() {
         return mFullConfiguration;
     }
@@ -170,11 +172,13 @@
     }
 
     /** Returns requested override configuration applied to this configuration container. */
+    @NonNull
     public Configuration getRequestedOverrideConfiguration() {
         return mRequestedOverrideConfiguration;
     }
 
     /** Returns the resolved override configuration. */
+    @NonNull
     Configuration getResolvedOverrideConfiguration() {
         return mResolvedOverrideConfiguration;
     }
@@ -203,6 +207,7 @@
      * Get merged override configuration from the top of the hierarchy down to this particular
      * instance. This should be reported to client as override config.
      */
+    @NonNull
     public Configuration getMergedOverrideConfiguration() {
         return mMergedOverrideConfiguration;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index b24ab93..86bbd1f 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -495,8 +495,10 @@
 
 
     DisplayAreaInfo getDisplayAreaInfo() {
-        DisplayAreaInfo info = new DisplayAreaInfo(mRemoteToken.toWindowContainerToken(),
+        final DisplayAreaInfo info = new DisplayAreaInfo(mRemoteToken.toWindowContainerToken(),
                 getDisplayContent().getDisplayId(), mFeatureId);
+        final RootDisplayArea root = getRootDisplayArea();
+        info.rootDisplayAreaId = root == null ? getDisplayContent().mFeatureId : root.mFeatureId;
         info.configuration.setTo(getConfiguration());
         return info;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 47d7c9d..3d7ac6c 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -25,6 +25,7 @@
 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
+import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
 
 import android.annotation.Nullable;
 import android.os.Bundle;
@@ -135,12 +136,6 @@
  */
 class DisplayAreaPolicyBuilder {
 
-    /**
-     * Key to specify the {@link RootDisplayArea} to attach the window to. Should be used by the
-     * function passed in from {@link #setSelectRootForWindowFunc(BiFunction)}
-     */
-    static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id";
-
     @Nullable private HierarchyBuilder mRootHierarchyBuilder;
     private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =
             new ArrayList<>();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3dbc517..c57a856 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -94,6 +94,7 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
 import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS;
@@ -116,7 +117,6 @@
 import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.DISPLAY_CONTENT;
@@ -361,6 +361,13 @@
     boolean mIsSizeForced = false;
 
     /**
+     * Overridden display size and metrics to activity window bounds. Set via
+     * "adb shell wm set-sandbox-display-apis". Default to true, since only disable for debugging.
+     * @see WindowManagerService#setSandboxDisplayApis(int, boolean)
+     */
+    private boolean mSandboxDisplayApis = true;
+
+    /**
      * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity}
      * but can be set from Settings or via shell command "adb shell wm density".
      * @see WindowManagerService#setForcedDisplayDensityForUser(int, int, int)
@@ -1004,6 +1011,8 @@
 
         mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
         mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
+        mAtmService.getTransitionController().registerLegacyListener(
+                mWmService.mActivityManagerAppTransitionNotifier);
         mAppTransition.registerListenerLocked(mFixedRotationTransitionListener);
         mAppTransitionController = new AppTransitionController(mWmService, this);
         mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
@@ -5355,7 +5364,6 @@
         portalWindowHandle.scaleFactor = 1f;
         portalWindowHandle.ownerPid = Process.myPid();
         portalWindowHandle.ownerUid = Process.myUid();
-        portalWindowHandle.portalToDisplayId = mDisplayId;
         return portalWindowHandle;
     }
 
@@ -5835,6 +5843,21 @@
         return true;
     }
 
+    /**
+     * Sets if Display APIs should be sandboxed to the activity window bounds.
+     */
+    void setSandboxDisplayApis(boolean sandboxDisplayApis) {
+        mSandboxDisplayApis = sandboxDisplayApis;
+    }
+
+    /**
+     * Returns {@code true} is Display APIs should be sandboxed to the activity window bounds,
+     * {@code false} otherwise. Default to true, unless set for debugging purposes.
+     */
+    boolean sandboxDisplayApis() {
+        return mSandboxDisplayApis;
+    }
+
     /** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
     class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 97c19ab..5b64546 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
@@ -39,6 +40,7 @@
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
 import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 import static android.view.ViewRootImpl.computeWindowBounds;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -333,6 +335,7 @@
     private static final Rect sTmpRect = new Rect();
     private static final Rect sTmpNavFrame = new Rect();
     private static final Rect sTmpStatusFrame = new Rect();
+    private static final Rect sTmpDecorFrame = new Rect();
     private static final Rect sTmpScreenDecorFrame = new Rect();
     private static final Rect sTmpLastParentFrame = new Rect();
     private static final Rect sTmpDisplayFrameBounds = new Rect();
@@ -430,8 +433,10 @@
 
         final int displayId = displayContent.getDisplayId();
 
-        mBarContentFrames.put(TYPE_STATUS_BAR, new Rect());
-        mBarContentFrames.put(TYPE_NAVIGATION_BAR, new Rect());
+        if (!INSETS_LAYOUT_GENERALIZATION) {
+            mBarContentFrames.put(TYPE_STATUS_BAR, new Rect());
+            mBarContentFrames.put(TYPE_NAVIGATION_BAR, new Rect());
+        }
 
         final Resources r = mContext.getResources();
         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
@@ -613,6 +618,8 @@
             }
         };
         displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
+        mService.mAtmService.getTransitionController().registerLegacyListener(
+                mAppTransitionListener);
         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
                 mService.mVrModeEnabled);
 
@@ -1079,7 +1086,9 @@
                 mStatusBar = win;
                 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
                         (displayFrames, windowState, rect) -> {
-                            rect.bottom = rect.top + getStatusBarHeight(displayFrames);
+                            if (!INSETS_LAYOUT_GENERALIZATION) {
+                                rect.bottom = rect.top + getStatusBarHeight(displayFrames);
+                            }
                         };
                 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
                 mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider);
@@ -1089,18 +1098,22 @@
                 mNavigationBar = win;
                 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
                         (displayFrames, windowState, inOutFrame) -> {
-
-                            // In Gesture Nav, navigation bar frame is larger than frame to
-                            // calculate inset.
-                            if (navigationBarPosition(displayFrames.mDisplayWidth,
-                                    displayFrames.mDisplayHeight,
-                                    displayFrames.mRotation) == NAV_BAR_BOTTOM
-                                    && !mNavButtonForcedVisible) {
-                                sTmpRect.set(inOutFrame);
-                                sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
-                                inOutFrame.top = sTmpRect.bottom
-                                        - getNavigationBarHeight(displayFrames.mRotation,
-                                        mDisplayContent.getConfiguration().uiMode);
+                            if (INSETS_LAYOUT_GENERALIZATION) {
+                                inOutFrame.inset(windowState.getLayoutingAttrs(
+                                        displayFrames.mRotation).providedInternalInsets);
+                            } else {
+                                // In Gesture Nav, navigation bar frame is larger than frame to
+                                // calculate inset.
+                                if (navigationBarPosition(displayFrames.mDisplayWidth,
+                                        displayFrames.mDisplayHeight,
+                                        displayFrames.mRotation) == NAV_BAR_BOTTOM
+                                        && !mNavButtonForcedVisible) {
+                                    sTmpRect.set(inOutFrame);
+                                    sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+                                    inOutFrame.top = sTmpRect.bottom
+                                            - getNavigationBarHeight(displayFrames.mRotation,
+                                            mDisplayContent.getConfiguration().uiMode);
+                                }
                             }
                         },
 
@@ -1161,7 +1174,14 @@
                                 mExtraNavBarAltPosition = getAltBarPosition(attrs);
                                 break;
                         }
-                        mDisplayContent.setInsetProvider(insetsType, win, null);
+                        if (!INSETS_LAYOUT_GENERALIZATION) {
+                            mDisplayContent.setInsetProvider(insetsType, win, null);
+                        } else {
+                            mDisplayContent.setInsetProvider(insetsType, win, (displayFrames,
+                                    windowState, inOutFrame) -> inOutFrame.inset(
+                                            windowState.getLayoutingAttrs(displayFrames.mRotation)
+                                                    .providedInternalInsets));
+                        }
                     }
                 }
                 break;
@@ -1252,8 +1272,17 @@
     }
 
     private int getStatusBarHeight(DisplayFrames displayFrames) {
-        return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
-                displayFrames.mDisplayCutoutSafe.top);
+        int statusBarHeight;
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            if (mStatusBar != null) {
+                statusBarHeight = mStatusBar.getLayoutingAttrs(displayFrames.mRotation).height;
+            } else {
+                statusBarHeight = 0;
+            }
+        } else {
+            statusBarHeight = mStatusBarHeightForRotation[displayFrames.mRotation];
+        }
+        return Math.max(statusBarHeight, displayFrames.mDisplayCutoutSafe.top);
     }
 
     WindowState getStatusBar() {
@@ -1388,7 +1417,7 @@
     /**
      * @return true if the system bars are forced to stay visible
      */
-    public boolean areSystemBarsForcedShownLw(WindowState windowState) {
+    public boolean areSystemBarsForcedShownLw() {
         return mForceShowSystemBars;
     }
 
@@ -1423,13 +1452,30 @@
             WindowFrames simulatedWindowFrames, SparseArray<Rect> contentFrames,
             Consumer<Rect> layout) {
         win.setSimulatedWindowFrames(simulatedWindowFrames);
+        final int requestedHeight = win.mRequestedHeight;
+        final int requestedWidth = win.mRequestedWidth;
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            // Without a full layout process, in order to layout the system bars correctly, we need
+            // to set the requested size and the initial display frames to the window.
+            WindowManager.LayoutParams params = win.getLayoutingAttrs(displayFrames.mRotation);
+            win.setRequestedSize(params.width, params.height);
+            sTmpDecorFrame.set(0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
+            simulatedWindowFrames.setFrames(sTmpDecorFrame /* parentFrame */,
+                    sTmpDecorFrame /* displayFrame */);
+            simulatedWindowFrames.mIsSimulatingDecorWindow = true;
+        }
         final Rect contentFrame = new Rect();
         try {
             layout.accept(contentFrame);
         } finally {
             win.setSimulatedWindowFrames(null);
+            if (INSETS_LAYOUT_GENERALIZATION) {
+                win.setRequestedSize(requestedWidth, requestedHeight);
+            }
         }
-        contentFrames.put(win.mAttrs.type, contentFrame);
+        if (!INSETS_LAYOUT_GENERALIZATION) {
+            contentFrames.put(win.mAttrs.type, contentFrame);
+        }
         mDisplayContent.getInsetsStateController().computeSimulatedState(
                 win, displayFrames, simulatedWindowFrames);
     }
@@ -1440,15 +1486,31 @@
      * some temporal states, but doesn't change the window frames used to show on screen.
      */
     void simulateLayoutDisplay(DisplayFrames displayFrames, SparseArray<Rect> barContentFrames) {
-        final WindowFrames simulatedWindowFrames = new WindowFrames();
         if (mNavigationBar != null) {
-            simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
-                    barContentFrames, contentFrame -> layoutNavigationBar(displayFrames,
-                            contentFrame));
+            final WindowFrames simulatedWindowFrames = new WindowFrames();
+            if (INSETS_LAYOUT_GENERALIZATION) {
+                simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
+                        barContentFrames,
+                        contentFrame -> simulateLayoutForContentFrame(displayFrames,
+                                mNavigationBar, contentFrame));
+            } else {
+                simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
+                        barContentFrames, contentFrame -> layoutNavigationBar(displayFrames,
+                                contentFrame));
+            }
         }
         if (mStatusBar != null) {
-            simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
-                    barContentFrames, contentFrame -> layoutStatusBar(displayFrames, contentFrame));
+            final WindowFrames simulatedWindowFrames = new WindowFrames();
+            if (INSETS_LAYOUT_GENERALIZATION) {
+                simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
+                        barContentFrames,
+                        contentFrame -> simulateLayoutForContentFrame(displayFrames,
+                                mStatusBar, contentFrame));
+            } else {
+                simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
+                        barContentFrames,
+                        contentFrame -> layoutStatusBar(displayFrames, contentFrame));
+            }
         }
     }
 
@@ -1467,7 +1529,7 @@
         windowFrames.setFrames(sTmpStatusFrame /* parentFrame */,
                 sTmpStatusFrame /* displayFrame */);
         // Let the status bar determine its size.
-        mStatusBar.computeFrameAndUpdateSourceFrame();
+        mStatusBar.computeFrameAndUpdateSourceFrame(displayFrames);
 
         // For layout, the status bar is always at the top with our fixed height.
         int statusBarBottom = displayFrames.mUnrestricted.top
@@ -1518,18 +1580,18 @@
         } else if (navBarPosition == NAV_BAR_RIGHT) {
             // Landscape screen; nav bar goes to the right.
             navigationFrame.left = Math.min(cutoutSafeUnrestricted.right, navigationFrame.right)
-                    - getNavigationBarWidth(rotation, uiMode);
+                    - getNavigationBarWidth(rotation, uiMode, navBarPosition);
         } else if (navBarPosition == NAV_BAR_LEFT) {
             // Seascape screen; nav bar goes to the left.
             navigationFrame.right = Math.max(cutoutSafeUnrestricted.left, navigationFrame.left)
-                    + getNavigationBarWidth(rotation, uiMode);
+                    + getNavigationBarWidth(rotation, uiMode, navBarPosition);
         }
 
         // Compute the final frame.
         final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
         windowFrames.setFrames(navigationFrame /* parentFrame */,
                 navigationFrame /* displayFrame */);
-        mNavigationBar.computeFrameAndUpdateSourceFrame();
+        mNavigationBar.computeFrameAndUpdateSourceFrame(displayFrames);
         sTmpRect.set(windowFrames.mFrame);
         sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
         contentFrame.set(sTmpRect);
@@ -1538,6 +1600,16 @@
         return navBarPosition;
     }
 
+    private void simulateLayoutForContentFrame(DisplayFrames displayFrames, WindowState win,
+            Rect simulatedContentFrame) {
+        layoutWindowLw(win, null /* attached */, displayFrames);
+        final Rect contentFrame = sTmpRect;
+        contentFrame.set(win.getLayoutingWindowFrames().mFrame);
+        // Excluding the display cutout before set to the simulated content frame.
+        contentFrame.intersect(displayFrames.mDisplayCutoutSafe);
+        simulatedContentFrame.set(contentFrame);
+    }
+
     private boolean canReceiveInput(WindowState win) {
         boolean notFocusable =
                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
@@ -1559,16 +1631,16 @@
      * @param displayFrames The display frames.
      */
     public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
-        if (win == mNavigationBar) {
+        if (win == mNavigationBar && !INSETS_LAYOUT_GENERALIZATION) {
             mNavigationBarPosition = layoutNavigationBar(displayFrames,
                     mBarContentFrames.get(TYPE_NAVIGATION_BAR));
             return;
         }
-        if ((win == mStatusBar && !canReceiveInput(win))) {
+        if ((win == mStatusBar && !canReceiveInput(win)) && !INSETS_LAYOUT_GENERALIZATION) {
             layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
             return;
         }
-        final WindowManager.LayoutParams attrs = win.getAttrs();
+        final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
 
         final int type = attrs.type;
         final int fl = attrs.flags;
@@ -1576,7 +1648,7 @@
         final int sim = attrs.softInputMode;
 
         displayFrames = win.getDisplayFrames(displayFrames);
-        final WindowFrames windowFrames = win.getWindowFrames();
+        final WindowFrames windowFrames = win.getLayoutingWindowFrames();
 
         sTmpLastParentFrame.set(windowFrames.mParentFrame);
         final Rect pf = windowFrames.mParentFrame;
@@ -1587,7 +1659,13 @@
         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
 
         final InsetsState state = win.getInsetsState();
-        computeWindowBounds(attrs, state, win.mToken.getBounds(), df);
+        if (windowFrames.mIsSimulatingDecorWindow && INSETS_LAYOUT_GENERALIZATION) {
+            // Override the bounds in window token has many side effects. Directly use the display
+            // frame set for the simulated layout for this case.
+            computeWindowBounds(attrs, state, df, df);
+        } else {
+            computeWindowBounds(attrs, state, win.mToken.getBounds(), df);
+        }
         if (attached == null) {
             pf.set(df);
             if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
@@ -1687,7 +1765,17 @@
             windowFrames.setContentChanged(true);
         }
 
-        win.computeFrameAndUpdateSourceFrame();
+        win.computeFrameAndUpdateSourceFrame(displayFrames);
+        if (INSETS_LAYOUT_GENERALIZATION && attrs.type == TYPE_STATUS_BAR) {
+            if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
+                // Make sure that the zone we're avoiding for the cutout is at least as tall as the
+                // status bar; otherwise fullscreen apps will end up cutting halfway into the status
+                // bar.
+                displayFrames.mDisplayCutoutSafe.top = Math.max(
+                        displayFrames.mDisplayCutoutSafe.top,
+                        windowFrames.mFrame.bottom);
+            }
+        }
     }
 
     WindowState getTopFullscreenOpaqueWindow() {
@@ -2116,18 +2204,47 @@
         return mUiContext;
     }
 
-    private int getNavigationBarWidth(int rotation, int uiMode) {
-        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
-            return mNavigationBarWidthForRotationInCarMode[rotation];
+    private int getNavigationBarWidth(int rotation, int uiMode, int position) {
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            if (mNavigationBar == null) {
+                return 0;
+            }
+            LayoutParams lp = mNavigationBar.mAttrs;
+            if (lp.paramsForRotation != null
+                    && lp.paramsForRotation.length == 4
+                    && lp.paramsForRotation[rotation] != null) {
+                lp = lp.paramsForRotation[rotation];
+            }
+            if (position == NAV_BAR_LEFT) {
+                if (lp.width > lp.providedInternalInsets.right) {
+                    return lp.width - lp.providedInternalInsets.right;
+                } else {
+                    return 0;
+                }
+            } else if (position == NAV_BAR_RIGHT) {
+                if (lp.width > lp.providedInternalInsets.left) {
+                    return lp.width - lp.providedInternalInsets.left;
+                } else {
+                    return 0;
+                }
+            }
+            return lp.width;
         } else {
-            return mNavigationBarWidthForRotationDefault[rotation];
+            if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+                return mNavigationBarWidthForRotationInCarMode[rotation];
+            } else {
+                return mNavigationBarWidthForRotationDefault[rotation];
+            }
         }
     }
 
     void notifyDisplayReady() {
         mHandler.post(() -> {
             final int displayId = getDisplayId();
-            getStatusBarManagerInternal().onDisplayReady(displayId);
+            StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+            if (statusBar != null) {
+                statusBar.onDisplayReady(displayId);
+            }
             final WallpaperManagerInternal wpMgr = LocalServices
                     .getService(WallpaperManagerInternal.class);
             if (wpMgr != null) {
@@ -2147,7 +2264,7 @@
         if (hasNavigationBar()) {
             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
             if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
-                width -= getNavigationBarWidth(rotation, uiMode);
+                width -= getNavigationBarWidth(rotation, uiMode, navBarPosition);
             }
         }
         if (displayCutout != null) {
@@ -2157,10 +2274,21 @@
     }
 
     private int getNavigationBarHeight(int rotation, int uiMode) {
-        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
-            return mNavigationBarHeightForRotationInCarMode[rotation];
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            if (mNavigationBar == null) {
+                return 0;
+            }
+            LayoutParams lp = mNavigationBar.getLayoutingAttrs(rotation);
+            if (lp.height < lp.providedInternalInsets.top) {
+                return 0;
+            }
+            return lp.height - lp.providedInternalInsets.top;
         } else {
-            return mNavigationBarHeightForRotationDefault[rotation];
+            if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+                return mNavigationBarHeightForRotationInCarMode[rotation];
+            } else {
+                return mNavigationBarHeightForRotationDefault[rotation];
+            }
         }
     }
 
@@ -2177,10 +2305,17 @@
      * @return navigation bar frame height
      */
     private int getNavigationBarFrameHeight(int rotation, int uiMode) {
-        if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
-            return mNavigationBarHeightForRotationInCarMode[rotation];
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            if (mNavigationBar == null) {
+                return 0;
+            }
+            return mNavigationBar.mAttrs.height;
         } else {
-            return mNavigationBarFrameHeightForRotationDefault[rotation];
+            if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+                return mNavigationBarHeightForRotationInCarMode[rotation];
+            } else {
+                return mNavigationBarFrameHeightForRotationDefault[rotation];
+            }
         }
     }
 
@@ -2301,9 +2436,9 @@
             if (position == NAV_BAR_BOTTOM) {
                 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
             } else if (position == NAV_BAR_RIGHT) {
-                outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
+                outInsets.right = getNavigationBarWidth(displayRotation, uiMode, position);
             } else if (position == NAV_BAR_LEFT) {
-                outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
+                outInsets.left = getNavigationBarWidth(displayRotation, uiMode, position);
             }
         }
 
@@ -2329,6 +2464,17 @@
 
     @NavigationBarPosition
     int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
+        if (INSETS_LAYOUT_GENERALIZATION && mNavigationBar != null) {
+            final int gravity = mNavigationBar.getLayoutingAttrs(displayRotation).gravity;
+            switch (gravity) {
+                case Gravity.LEFT:
+                    return NAV_BAR_LEFT;
+                case Gravity.RIGHT:
+                    return NAV_BAR_RIGHT;
+                default:
+                    return NAV_BAR_BOTTOM;
+            }
+        }
         if (navigationBarCanMove() && displayWidth > displayHeight) {
             if (displayRotation == Surface.ROTATION_270) {
                 return NAV_BAR_LEFT;
@@ -2486,8 +2632,6 @@
         final WindowState win = winCandidate;
         mSystemUiControllingWindow = win;
 
-        mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
-
         final boolean inSplitScreen =
                 mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
         if (inSplitScreen) {
@@ -2634,19 +2778,22 @@
     }
 
     private int updateSystemBarsLw(WindowState win, int disableFlags) {
-        final boolean dockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
-                .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-        final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
+        final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+        final boolean multiWindowTaskVisible =
+                defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
+                        || defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_MULTI_WINDOW);
+        final boolean freeformRootTaskVisible =
+                defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM);
 
-        // We need to force system bars when the docked root task is visible, when the freeform
-        // root task is focused but also when we are resizing for the transitions when docked
-        // root task visibility changes.
-        mForceShowSystemBars = dockedRootTaskVisible || win.inFreeformWindowingMode() || resizing;
+        // We need to force showing system bars when the multi-window or freeform root task is
+        // visible.
+        mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible;
+        mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
 
         int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
-
         appearance = configureStatusBarOpacity(appearance);
-        appearance = configureNavBarOpacity(appearance, dockedRootTaskVisible, resizing);
+        appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible,
+                freeformRootTaskVisible);
 
         final boolean requestHideNavBar = !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
         final long now = SystemClock.uptimeMillis();
@@ -2692,7 +2839,24 @@
 
     private Rect getBarContentFrameForWindow(WindowState win, int windowType) {
         final Rect rotatedBarFrame = win.mToken.getFixedRotationBarContentFrame(windowType);
-        return rotatedBarFrame != null ? rotatedBarFrame : mBarContentFrames.get(windowType);
+        if (rotatedBarFrame != null) {
+            return rotatedBarFrame;
+        }
+        if (!INSETS_LAYOUT_GENERALIZATION) {
+            return mBarContentFrames.get(windowType);
+        }
+        // We only need a window specific information for the fixed rotation, use raw insets state
+        // for all other cases.
+        InsetsState insetsState = mDisplayContent.getInsetsStateController().getRawInsetsState();
+        final Rect tmpRect = new Rect();
+        if (windowType == TYPE_NAVIGATION_BAR) {
+            tmpRect.set(insetsState.getSource(InsetsState.ITYPE_NAVIGATION_BAR).getFrame());
+        }
+        if (windowType == TYPE_STATUS_BAR) {
+            tmpRect.set(insetsState.getSource(InsetsState.ITYPE_STATUS_BAR).getFrame());
+        }
+        tmpRect.intersect(mDisplayContent.mDisplayFrames.mDisplayCutoutSafe);
+        return tmpRect;
     }
 
     /**
@@ -2748,10 +2912,8 @@
      * @return the current visibility flags with the nav-bar opacity related flags toggled based
      *         on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
      */
-    private int configureNavBarOpacity(int appearance, boolean dockedRootTaskVisible,
-            boolean isDockedDividerResizing) {
-        final boolean freeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
-                .isRootTaskVisible(WINDOWING_MODE_FREEFORM);
+    private int configureNavBarOpacity(int appearance, boolean multiWindowTaskVisible,
+            boolean freeformRootTaskVisible) {
         final boolean fullscreenDrawsBackground =
                 drawsBarBackground(mTopFullscreenOpaqueWindowState);
         final boolean dockedDrawsBackground =
@@ -2760,26 +2922,18 @@
         if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
             if (fullscreenDrawsBackground && dockedDrawsBackground) {
                 appearance = clearNavBarOpaqueFlag(appearance);
-            } else if (dockedRootTaskVisible) {
-                appearance = setNavBarOpaqueFlag(appearance);
             }
         } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
-            if (dockedRootTaskVisible || freeformRootTaskVisible || isDockedDividerResizing) {
+            if (multiWindowTaskVisible || freeformRootTaskVisible) {
                 if (mIsFreeformWindowOverlappingWithNavBar) {
                     appearance = clearNavBarOpaqueFlag(appearance);
-                } else {
-                    appearance = setNavBarOpaqueFlag(appearance);
                 }
             } else if (fullscreenDrawsBackground) {
                 appearance = clearNavBarOpaqueFlag(appearance);
             }
         } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
-            if (isDockedDividerResizing) {
-                appearance = setNavBarOpaqueFlag(appearance);
-            } else if (freeformRootTaskVisible) {
+            if (freeformRootTaskVisible) {
                 appearance = clearNavBarOpaqueFlag(appearance);
-            } else {
-                appearance = setNavBarOpaqueFlag(appearance);
             }
         }
 
@@ -2791,10 +2945,6 @@
         return appearance;
     }
 
-    private int setNavBarOpaqueFlag(int appearance) {
-        return appearance | APPEARANCE_OPAQUE_NAVIGATION_BARS;
-    }
-
     private int clearNavBarOpaqueFlag(int appearance) {
         return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS;
     }
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 316c20b..2f0d703 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -24,22 +24,22 @@
 
 /** Helper class to ensure activities are in the right visible state for a container. */
 class EnsureActivitiesVisibleHelper {
-    private final Task mTask;
+    private final TaskFragment mTaskFragment;
     private ActivityRecord mTop;
     private ActivityRecord mStarting;
     private boolean mAboveTop;
     private boolean mContainerShouldBeVisible;
-    private boolean mBehindFullscreenActivity;
+    private boolean mBehindFullyOccludedContainer;
     private int mConfigChanges;
     private boolean mPreserveWindows;
     private boolean mNotifyClients;
 
-    EnsureActivitiesVisibleHelper(Task container) {
-        mTask = container;
+    EnsureActivitiesVisibleHelper(TaskFragment container) {
+        mTaskFragment = container;
     }
 
     /**
-     * Update all attributes except {@link mTask} to use in subsequent calculations.
+     * Update all attributes except {@link mTaskFragment} to use in subsequent calculations.
      *
      * @param starting The activity that is being started
      * @param configChanges Parts of the configuration that changed for this activity for evaluating
@@ -51,12 +51,12 @@
     void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
             boolean notifyClients) {
         mStarting = starting;
-        mTop = mTask.topRunningActivity();
+        mTop = mTaskFragment.topRunningActivity();
         // If the top activity is not fullscreen, then we need to make sure any activities under it
         // are now visible.
         mAboveTop = mTop != null;
-        mContainerShouldBeVisible = mTask.shouldBeVisible(mStarting);
-        mBehindFullscreenActivity = !mContainerShouldBeVisible;
+        mContainerShouldBeVisible = mTaskFragment.shouldBeVisible(mStarting);
+        mBehindFullyOccludedContainer = !mContainerShouldBeVisible;
         mConfigChanges = configChanges;
         mPreserveWindows = preserveWindows;
         mNotifyClients = notifyClients;
@@ -85,22 +85,35 @@
             Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop
                     + " configChanges=0x" + Integer.toHexString(configChanges));
         }
-        if (mTop != null) {
-            mTask.checkTranslucentActivityWaiting(mTop);
+        if (mTop != null && mTaskFragment.asTask() != null) {
+            // TODO(14709632): Check if this needed to be implemented in TaskFragment.
+            mTaskFragment.asTask().checkTranslucentActivityWaiting(mTop);
         }
 
         // We should not resume activities that being launched behind because these
         // activities are actually behind other fullscreen activities, but still required
         // to be visible (such as performing Recents animation).
         final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
-                && mTask.isTopActivityFocusable()
-                && (starting == null || !starting.isDescendantOf(mTask));
+                && mTaskFragment.isTopActivityFocusable()
+                && (starting == null || !starting.isDescendantOf(mTaskFragment));
 
-        mTask.forAllActivities(a -> {
-            setActivityVisibilityState(a, starting, resumeTopActivity);
-        });
-        if (mTask.mAtmService.getTransitionController().getTransitionPlayer() != null) {
-            mTask.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
+        for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer child = mTaskFragment.mChildren.get(i);
+            if (child.asTaskFragment() != null) {
+                final TaskFragment childTaskFragment = child.asTaskFragment();
+                childTaskFragment.updateActivityVisibilities(starting, configChanges,
+                        preserveWindows, notifyClients);
+                mBehindFullyOccludedContainer = childTaskFragment.getBounds().equals(
+                        mTaskFragment.getBounds());
+                if (mAboveTop && mTop.getTaskFragment() == childTaskFragment) {
+                    mAboveTop = false;
+                }
+            } else if (child.asActivityRecord() != null) {
+                setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);
+            }
+        }
+        if (mTaskFragment.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+            mTaskFragment.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
         }
     }
 
@@ -112,7 +125,7 @@
         }
         mAboveTop = false;
 
-        r.updateVisibilityIgnoringKeyguard(mBehindFullscreenActivity);
+        r.updateVisibilityIgnoringKeyguard(mBehindFullyOccludedContainer);
         final boolean reallyVisible = r.shouldBeVisibleUnchecked();
 
         // Check whether activity should be visible without Keyguard influence
@@ -122,11 +135,11 @@
                 if (DEBUG_VISIBILITY) {
                     Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
                             + " containerVisible=" + mContainerShouldBeVisible
-                            + " behindFullscreen=" + mBehindFullscreenActivity);
+                            + " behindFullyOccluded=" + mBehindFullyOccludedContainer);
                 }
-                mBehindFullscreenActivity = true;
+                mBehindFullyOccludedContainer = true;
             } else {
-                mBehindFullscreenActivity = false;
+                mBehindFullyOccludedContainer = false;
             }
         }
 
@@ -173,24 +186,25 @@
                 Slog.v(TAG_VISIBILITY, "Make invisible? " + r
                         + " finishing=" + r.finishing + " state=" + r.getState()
                         + " containerShouldBeVisible=" + mContainerShouldBeVisible
-                        + " behindFullscreenActivity=" + mBehindFullscreenActivity
+                        + " behindFullyOccludedContainer=" + mBehindFullyOccludedContainer
                         + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
             }
             r.makeInvisible();
         }
 
-        if (!mBehindFullscreenActivity && mTask.isActivityTypeHome() && r.isRootOfTask()) {
+        if (!mBehindFullyOccludedContainer && mTaskFragment.isActivityTypeHome()
+                && r.isRootOfTask()) {
             if (DEBUG_VISIBILITY) {
-                Slog.v(TAG_VISIBILITY, "Home task: at " + mTask
+                Slog.v(TAG_VISIBILITY, "Home task: at " + mTaskFragment
                         + " containerShouldBeVisible=" + mContainerShouldBeVisible
-                        + " behindFullscreenActivity=" + mBehindFullscreenActivity);
+                        + " behindOccludedParentContainer=" + mBehindFullyOccludedContainer);
             }
             // No other task in the root home task should be visible behind the home activity.
             // Home activities is usually a translucent activity with the wallpaper behind
             // them. However, when they don't have the wallpaper behind them, we want to
             // show activities in the next application root task behind them vs. another
             // task in the root home task like recents.
-            mBehindFullscreenActivity = true;
+            mBehindFullyOccludedContainer = true;
         }
     }
 
@@ -219,7 +233,8 @@
             r.setVisibility(true);
         }
         if (r != starting) {
-            mTask.mTaskSupervisor.startSpecificActivity(r, andResume, true /* checkConfig */);
+            mTaskFragment.mTaskSupervisor.startSpecificActivity(r, andResume,
+                    true /* checkConfig */);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index da47328..4f6a693 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -29,6 +29,7 @@
 import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Trace;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsSource;
@@ -90,6 +91,16 @@
         onSourceChanged();
     }
 
+    @Override
+    void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
+        if (target != null && target.getWindow() != null) {
+            // ime control target could be a different window.
+            // Refer WindowState#getImeControlTarget().
+            target = target.getWindow().getImeControlTarget();
+        }
+        super.updateControlForTarget(target, force);
+    }
+
     private void onSourceChanged() {
         if (mLastSource.equals(mSource)) {
             return;
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 747d365..f3b9cdf 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
+import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
 
 import android.animation.ArgbEvaluator;
 import android.animation.ValueAnimator;
@@ -420,7 +421,7 @@
         }
 
         final Bundle options = new Bundle();
-        options.putInt(DisplayAreaPolicyBuilder.KEY_ROOT_DISPLAY_AREA_ID, rootDisplayAreaId);
+        options.putInt(KEY_ROOT_DISPLAY_AREA_ID, rootDisplayAreaId);
         return options;
     }
 
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8c781a1..eb5ab83 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -18,7 +18,6 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
@@ -617,7 +616,6 @@
         inputWindowHandle.setScaleFactor(1f);
         inputWindowHandle.setLayoutParamsFlags(
                 FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
-        inputWindowHandle.setPortalToDisplayId(INVALID_DISPLAY);
         inputWindowHandle.clearTouchableRegion();
         inputWindowHandle.setTouchableRegionCrop(null);
     }
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index 7a4d13c..b4e11ff 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -223,14 +223,6 @@
         mChanged = true;
     }
 
-    void setPortalToDisplayId(int displayId) {
-        if (mHandle.portalToDisplayId == displayId) {
-            return;
-        }
-        mHandle.portalToDisplayId = displayId;
-        mChanged = true;
-    }
-
     void setFrame(int left, int top, int right, int bottom) {
         if (mHandle.frameLeft == left && mHandle.frameTop == top && mHandle.frameRight == right
                 && mHandle.frameBottom == bottom) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f2f1926..afffe16 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -18,8 +18,6 @@
 
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
 import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
@@ -55,6 +53,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.DisplayThread;
+import com.android.server.statusbar.StatusBarManagerInternal;
 
 /**
  * Policy that implements who gets control over the windows generating insets.
@@ -135,11 +134,8 @@
             abortTransient();
         }
         mFocusedWin = focusedWin;
-        boolean forceShowsSystemBarsForWindowingMode = forceShowsSystemBarsForWindowingMode();
-        InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin,
-                forceShowsSystemBarsForWindowingMode);
-        InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin,
-                forceShowsSystemBarsForWindowingMode);
+        InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin);
+        InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin);
         mStateController.onBarControlTargetChanged(statusControlTarget,
                 getFakeControlTarget(focusedWin, statusControlTarget),
                 navControlTarget,
@@ -167,8 +163,12 @@
             changed = true;
         }
         if (changed) {
-            mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
-                    mShowingTransientTypes.toArray());
+            StatusBarManagerInternal statusBarManagerInternal =
+                    mPolicy.getStatusBarManagerInternal();
+            if (statusBarManagerInternal != null) {
+                statusBarManagerInternal.showTransient(
+                        mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
+            }
             updateBarControlTarget(mFocusedWin);
 
             // The leashes can be created while updating bar control target. The surface transaction
@@ -282,9 +282,11 @@
                     abortTypes.add(type);
                 }
             }
-            if (abortTypes.size() > 0) {
-                mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
-                        abortTypes.toArray());
+            StatusBarManagerInternal statusBarManagerInternal =
+                    mPolicy.getStatusBarManagerInternal();
+            if (abortTypes.size() > 0 && statusBarManagerInternal != null) {
+                statusBarManagerInternal.abortTransient(
+                        mDisplayContent.getDisplayId(), abortTypes.toArray());
             }
         }
     }
@@ -294,8 +296,11 @@
      * updateBarControlTarget(mFocusedWin) after this invocation.
      */
     private void abortTransient() {
-        mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
-                mShowingTransientTypes.toArray());
+        StatusBarManagerInternal statusBarManagerInternal = mPolicy.getStatusBarManagerInternal();
+        if (statusBarManagerInternal != null) {
+            statusBarManagerInternal.abortTransient(
+                    mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
+        }
         mShowingTransientTypes.clear();
     }
 
@@ -304,8 +309,7 @@
         return realControlTarget == mDummyControlTarget ? focused : null;
     }
 
-    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
-            boolean forceShowsSystemBarsForWindowingMode) {
+    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
         if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
             return mDummyControlTarget;
         }
@@ -319,10 +323,9 @@
                     focusedWin.mAttrs.packageName);
             return mDisplayContent.mRemoteInsetsControlTarget;
         }
-        if (forceShowsSystemBarsForWindowingMode) {
-            // Status bar is forcibly shown for the windowing mode which is a steady state.
-            // We don't want the client to control the status bar, and we will dispatch the real
-            // visibility of status bar to the client.
+        if (mPolicy.areSystemBarsForcedShownLw()) {
+            // Status bar is forcibly shown. We don't want the client to control the status bar, and
+            // we will dispatch the real visibility of status bar to the client.
             return null;
         }
         if (forceShowsStatusBarTransiently()) {
@@ -350,8 +353,7 @@
                 && !win.inMultiWindowMode();
     }
 
-    private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin,
-            boolean forceShowsSystemBarsForWindowingMode) {
+    private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
         final WindowState imeWin = mDisplayContent.mInputMethodWindow;
         if (imeWin != null && imeWin.isVisible()) {
             // Force showing navigation bar while IME is visible.
@@ -369,10 +371,9 @@
                     focusedWin.mAttrs.packageName);
             return mDisplayContent.mRemoteInsetsControlTarget;
         }
-        if (forceShowsSystemBarsForWindowingMode) {
-            // Navigation bar is forcibly shown for the windowing mode which is a steady state.
-            // We don't want the client to control the navigation bar, and we will dispatch the real
-            // visibility of navigation bar to the client.
+        if (mPolicy.areSystemBarsForcedShownLw()) {
+            // Navigation bar is forcibly shown. We don't want the client to control the navigation
+            // bar, and we will dispatch the real visibility of navigation bar to the client.
             return null;
         }
         if (forceShowsNavigationBarTransiently()) {
@@ -417,19 +418,6 @@
                 && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
     }
 
-    private boolean forceShowsSystemBarsForWindowingMode() {
-        final boolean isDockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
-                .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-        final boolean isFreeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
-                .isRootTaskVisible(WINDOWING_MODE_FREEFORM);
-        final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing();
-
-        // We need to force system bars when the docked root task is visible, when the freeform
-        // root task is visible but also when we are resizing for the transitions when docked
-        // root task visibility changes.
-        return isDockedRootTaskVisible || isFreeformRootTaskVisible || isResizing;
-    }
-
     @VisibleForTesting
     void startAnimation(boolean show, Runnable callback) {
         int typesReady = 0;
@@ -474,8 +462,12 @@
             final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN;
             if (mState != state) {
                 mState = state;
-                mPolicy.getStatusBarManagerInternal().setWindowState(
-                        mDisplayContent.getDisplayId(), mId, state);
+                StatusBarManagerInternal statusBarManagerInternal =
+                        mPolicy.getStatusBarManagerInternal();
+                if (statusBarManagerInternal != null) {
+                    statusBarManagerInternal.setWindowState(
+                            mDisplayContent.getDisplayId(), mId, state);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 7daebff..cbd1314 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -307,11 +307,6 @@
             // to control the window for now.
             return;
         }
-        if (target != null && target.getWindow() != null) {
-            // ime control target could be a different window.
-            // Refer WindowState#getImeControlTarget().
-            target = target.getWindow().getImeControlTarget();
-        }
 
         if (mWin != null && mWin.getSurfaceControl() == null) {
             // if window doesn't have a surface, set it null and return.
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 7174e68..eb7087c 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -21,7 +21,6 @@
 import android.graphics.Color;
 
 import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -105,12 +104,20 @@
      * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and
      * the framework implementation will be used to determine the aspect ratio.
      */
-    @VisibleForTesting
     void setFixedOrientationLetterboxAspectRatio(float aspectRatio) {
         mFixedOrientationLetterboxAspectRatio = aspectRatio;
     }
 
     /**
+     * Resets the aspect ratio of letterbox for fixed orientation to {@link
+     * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}.
+     */
+    void resetFixedOrientationLetterboxAspectRatio() {
+        mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
+                com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
+    }
+
+    /**
      * Gets the aspect ratio of letterbox for fixed orientation.
      */
     float getFixedOrientationLetterboxAspectRatio() {
@@ -118,6 +125,25 @@
     }
 
     /**
+     * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
+     * both it and a value of {@link
+     * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
+     * and corners of the activity won't be rounded.
+     */
+    void setLetterboxActivityCornersRadius(int cornersRadius) {
+        mLetterboxActivityCornersRadius = cornersRadius;
+    }
+
+    /**
+     * Resets corners raidus for activities presented in the letterbox mode to {@link
+     * com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
+     */
+    void resetLetterboxActivityCornersRadius() {
+        mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_letterboxActivityCornersRadius);
+    }
+
+    /**
      * Whether corners of letterboxed activities are rounded.
      */
     boolean isLetterboxActivityCornersRounded() {
@@ -140,6 +166,25 @@
         return mLetterboxBackgroundColor;
     }
 
+
+    /**
+     * Sets color of letterbox background which is used when {@link
+     * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
+     * fallback for other backfround types.
+     */
+    void setLetterboxBackgroundColor(Color color) {
+        mLetterboxBackgroundColor = color;
+    }
+
+    /**
+     * Resets color of letterbox background to {@link
+     * com.android.internal.R.color.config_letterboxBackgroundColor}.
+     */
+    void resetLetterboxBackgroundColor() {
+        mLetterboxBackgroundColor = Color.valueOf(mContext.getResources().getColor(
+                com.android.internal.R.color.config_letterboxBackgroundColor));
+    }
+
     /**
      * Gets {@link LetterboxBackgroundType} specified in {@link
      * com.android.internal.R.integer.config_letterboxBackgroundType} or over via ADB command.
@@ -149,6 +194,19 @@
         return mLetterboxBackgroundType;
     }
 
+    /** Sets letterbox background type. */
+    void setLetterboxBackgroundType(@LetterboxBackgroundType int backgroundType) {
+        mLetterboxBackgroundType = backgroundType;
+    }
+
+    /**
+     * Resets cletterbox background type to {@link
+     * com.android.internal.R.integer.config_letterboxBackgroundType}.
+     */
+    void resetLetterboxBackgroundType() {
+        mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
+    }
+
     /** Returns a string representing the given {@link LetterboxBackgroundType}. */
     static String letterboxBackgroundTypeToString(
             @LetterboxBackgroundType int backgroundType) {
@@ -178,6 +236,27 @@
     }
 
     /**
+     * Overrides alpha of a black scrim shown over wallpaper for {@link
+     * #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link mLetterboxBackgroundType}.
+     *
+     * <p>If given value is < 0 or >= 1, both it and a value of {@link
+     * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored
+     * and 0.0 (transparent) is instead.
+     */
+    void setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha) {
+        mLetterboxBackgroundWallpaperDarkScrimAlpha = alpha;
+    }
+
+    /**
+     * Resets alpha of a black scrim shown over wallpaper letterbox background to {@link
+     * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha}.
+     */
+    void resetLetterboxBackgroundWallpaperDarkScrimAlpha() {
+        mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(
+                com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
+    }
+
+    /**
      * Gets alpha of a black scrim shown over wallpaper letterbox background.
      */
     float getLetterboxBackgroundWallpaperDarkScrimAlpha() {
@@ -185,6 +264,28 @@
     }
 
     /**
+     * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in
+     * {@link mLetterboxBackgroundType}.
+     *
+     * <p> If given value <= 0, both it and a value of {@link
+     * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored
+     * and 0 is used instead.
+     */
+    void setLetterboxBackgroundWallpaperBlurRadius(int radius) {
+        mLetterboxBackgroundWallpaperBlurRadius = radius;
+    }
+
+    /**
+     * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
+     * mLetterboxBackgroundType} to {@link
+     * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}.
+     */
+    void resetLetterboxBackgroundWallpaperBlurRadius() {
+        mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
+    }
+
+    /**
      * Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
      * mLetterboxBackgroundType}.
      */
@@ -211,9 +312,17 @@
      * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and
      * central position (0.5) is used.
      */
-    @VisibleForTesting
     void setLetterboxHorizontalPositionMultiplier(float multiplier) {
         mLetterboxHorizontalPositionMultiplier = multiplier;
     }
 
+    /**
+     * Resets horizontal position of a center of the letterboxed app window to {@link
+     * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
+     */
+    void resetLetterboxHorizontalPositionMultiplier() {
+        mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
+                com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
+    }
+
 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index a10b5d6..7cd9164 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -25,6 +25,8 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
@@ -149,8 +151,7 @@
 
         // Invisible activity should be stopped. If the recents activity is alive and its doesn't
         // need to relaunch by current configuration, then it may be already in stopped state.
-        if (!targetActivity.isState(Task.ActivityState.STOPPING,
-                Task.ActivityState.STOPPED)) {
+        if (!targetActivity.isState(STOPPING, STOPPED)) {
             // Add to stopping instead of stop immediately. So the client has the chance to perform
             // traversal in non-stopped state (ViewRootImpl.mStopped) that would initialize more
             // things (e.g. the measure can be done earlier). The actual stop will be performed when
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6242b97..08c126a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -37,10 +37,10 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
 import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_PIP;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -53,6 +53,11 @@
 import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -70,14 +75,9 @@
 import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT;
 import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER;
 import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
-import static com.android.server.wm.Task.ActivityState.FINISHING;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
 import static com.android.server.wm.Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
 import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
-import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -1865,7 +1865,7 @@
         if (focusedRootTask == null) {
             return null;
         }
-        final ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
+        final ActivityRecord resumedActivity = focusedRootTask.getTopResumedActivity();
         if (resumedActivity != null && resumedActivity.app != null) {
             return resumedActivity;
         }
@@ -1887,11 +1887,11 @@
         // foreground.
         WindowProcessController fgApp = getItemFromRootTasks(rootTask -> {
             if (isTopDisplayFocusedRootTask(rootTask)) {
-                final ActivityRecord resumedActivity = rootTask.getResumedActivity();
+                final ActivityRecord resumedActivity = rootTask.getTopResumedActivity();
                 if (resumedActivity != null) {
                     return resumedActivity.app;
-                } else if (rootTask.getPausingActivity() != null) {
-                    return rootTask.getPausingActivity().app;
+                } else if (rootTask.getTopPausingActivity() != null) {
+                    return rootTask.getTopPausingActivity().app;
                 }
             }
             return null;
@@ -1917,7 +1917,8 @@
                     return;
                 }
 
-                if (rootTask.getVisibility(null /*starting*/) == TASK_VISIBILITY_INVISIBLE) {
+                if (rootTask.getVisibility(null /* starting */)
+                        == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
                     return;
                 }
 
@@ -2182,7 +2183,7 @@
                 // display area, so reparent.
                 rootTask.reparent(taskDisplayArea, true /* onTop */);
             }
-            mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CHANGE, rootTask);
+            mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_PIP, rootTask);
 
             // Defer the windowing mode change until after the transition to prevent the activity
             // from doing work and changing the activity visuals while animating
@@ -2382,7 +2383,9 @@
                 if (displayShouldSleep) {
                     rootTask.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
-                    rootTask.awakeFromSleepingLocked();
+                    rootTask.forAllLeafTasksAndLeafTaskFragments(
+                            taskFragment -> taskFragment.awakeFromSleeping(),
+                            true /* traverseTopToBottom */);
                     if (rootTask.isFocusedRootTaskOnDisplay()
                             && !mTaskSupervisor.getKeyguardController()
                             .isKeyguardOrAodShowing(display.mDisplayId)) {
@@ -2744,8 +2747,8 @@
 
         if (DEBUG_SWITCH) {
             Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.getState()
-                    + " resumed=" + r.getTask().getResumedActivity() + " pausing="
-                    + r.getTask().getPausingActivity() + " for reason "
+                    + " resumed=" + r.getTask().getTopResumedActivity() + " pausing="
+                    + r.getTask().getTopPausingActivity() + " for reason "
                     + mDestroyAllActivitiesReason);
         }
 
@@ -3332,7 +3335,7 @@
             if (rootTask == null || !rootTask.hasActivity()) {
                 continue;
             }
-            final ActivityRecord resumedActivity = rootTask.getResumedActivity();
+            final ActivityRecord resumedActivity = rootTask.getTopResumedActivity();
             if (resumedActivity == null || !resumedActivity.idle) {
                 ProtoLog.d(WM_DEBUG_STATES, "allResumedActivitiesIdle: rootTask=%d %s "
                         + "not idle", rootTask.getRootTaskId(), resumedActivity);
@@ -3347,7 +3350,7 @@
     boolean allResumedActivitiesVisible() {
         boolean[] foundResumed = {false};
         final boolean foundInvisibleResumedActivity = forAllRootTasks(rootTask -> {
-            final ActivityRecord r = rootTask.getResumedActivity();
+            final ActivityRecord r = rootTask.getTopResumedActivity();
             if (r != null) {
                 if (!r.nowVisible) {
                     return true;
@@ -3365,7 +3368,7 @@
     boolean allPausedActivitiesComplete() {
         boolean[] pausing = {true};
         final boolean hasActivityNotCompleted = forAllLeafTasks(task -> {
-            final ActivityRecord r = task.getPausingActivity();
+            final ActivityRecord r = task.getTopPausingActivity();
             if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
                 ProtoLog.d(WM_DEBUG_STATES, "allPausedActivitiesComplete: "
                         + "r=%s state=%s", r, r.getState());
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 7ba772c..1533245 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -43,7 +43,11 @@
 
     // Comparator to sort by last active time (descending)
     private static final Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR =
-            (o1, o2) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime);
+            (o1, o2) -> {
+                return o1.lastActiveTime == o2.lastActiveTime
+                        ? Integer.signum(o2.mTaskId - o1.mTaskId) :
+                        Long.signum(o2.lastActiveTime - o1.lastActiveTime);
+            };
 
     private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 325f10f..d3a7af5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -27,13 +27,10 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
 import static android.app.WindowConfiguration.windowingModeToString;
@@ -43,7 +40,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
-import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -53,9 +49,6 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -65,7 +58,6 @@
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
-import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -83,21 +75,18 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STARTED;
 import static com.android.server.wm.ActivityRecord.TRANSFER_SPLASH_SCREEN_COPYING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
@@ -110,7 +99,6 @@
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
@@ -121,21 +109,12 @@
 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.ActivityState.STARTED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
 import static com.android.server.wm.TaskProto.AFFINITY;
 import static com.android.server.wm.TaskProto.BOUNDS;
 import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
-import static com.android.server.wm.TaskProto.DISPLAY_ID;
 import static com.android.server.wm.TaskProto.FILLS_PARENT;
 import static com.android.server.wm.TaskProto.HAS_CHILD_PIP_ACTIVITY;
 import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS;
-import static com.android.server.wm.TaskProto.MIN_HEIGHT;
-import static com.android.server.wm.TaskProto.MIN_WIDTH;
 import static com.android.server.wm.TaskProto.ORIG_ACTIVITY;
 import static com.android.server.wm.TaskProto.REAL_ACTIVITY;
 import static com.android.server.wm.TaskProto.RESIZE_MODE;
@@ -143,7 +122,7 @@
 import static com.android.server.wm.TaskProto.ROOT_TASK_ID;
 import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
 import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
-import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
+import static com.android.server.wm.TaskProto.TASK_FRAGMENT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK;
@@ -168,14 +147,7 @@
 import android.app.IActivityController;
 import android.app.PictureInPictureParams;
 import android.app.RemoteAction;
-import android.app.ResultInfo;
 import android.app.TaskInfo;
-import android.app.WindowConfiguration;
-import android.app.servertransaction.ActivityResultItem;
-import android.app.servertransaction.ClientTransaction;
-import android.app.servertransaction.NewIntentItem;
-import android.app.servertransaction.PauseActivityItem;
-import android.app.servertransaction.ResumeActivityItem;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -244,23 +216,21 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
-class Task extends WindowContainer<WindowContainer> {
+/**
+ * {@link Task} is a TaskFragment that can contain a group of activities to perform a certain job.
+ * Activities of the same task affinities usually group in the same {@link Task}. A {@link Task}
+ * can also be an entity that showing in the Recents Screen for a job that user interacted with.
+ * A {@link Task} can also contain other {@link Task}s.
+ */
+class Task extends TaskFragment {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
-    static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
-    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     static final String TAG_TASKS = TAG + POSTFIX_TASKS;
-    private static final String TAG_APP = TAG + POSTFIX_APP;
     static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
-    private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
-    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
-    private static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
-    private static final String TAG_STATES = TAG + POSTFIX_STATES;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
     private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
@@ -303,10 +273,6 @@
     private static final String ATTR_LAST_SNAPSHOT_CONTENT_INSETS = "last_snapshot_content_insets";
     private static final String ATTR_LAST_SNAPSHOT_BUFFER_SIZE = "last_snapshot_buffer_size";
 
-    // Set to false to disable the preview that is shown while a new activity
-    // is being started.
-    private static final boolean SHOW_APP_STARTING_PREVIEW = true;
-
     // How long to wait for all background Activities to redraw following a call to
     // convertToTranslucent().
     private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
@@ -315,7 +281,6 @@
     // code.
     static final int PERSIST_TASK_VERSION = 1;
 
-    static final int INVALID_MIN_SIZE = -1;
     private float mShadowRadius = 0;
 
     /**
@@ -335,36 +300,6 @@
     // Do not move the root task as a part of reparenting
     static final int REPARENT_LEAVE_ROOT_TASK_IN_PLACE = 2;
 
-    @IntDef(prefix = {"TASK_VISIBILITY"}, value = {
-            TASK_VISIBILITY_VISIBLE,
-            TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
-            TASK_VISIBILITY_INVISIBLE,
-    })
-    @interface TaskVisibility {}
-
-    /** Task is visible. No other tasks on top that fully or partially occlude it. */
-    static final int TASK_VISIBILITY_VISIBLE = 0;
-
-    /** Task is partially occluded by other translucent task(s) on top of it. */
-    static final int TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
-
-    /** Task is completely invisible. */
-    static final int TASK_VISIBILITY_INVISIBLE = 2;
-
-    enum ActivityState {
-        INITIALIZING,
-        STARTED,
-        RESUMED,
-        PAUSING,
-        PAUSED,
-        STOPPING,
-        STOPPED,
-        FINISHING,
-        DESTROYING,
-        DESTROYED,
-        RESTARTING_PROCESS
-    }
-
     // The topmost Activity passed to convertToTranslucent(). When non-null it means we are
     // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they
     // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the
@@ -446,7 +381,6 @@
 
     CharSequence lastDescription; // Last description captured for this item.
 
-    Task mAdjacentTask; // Task adjacent to this one.
     int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
     Task mPrevAffiliate; // previous task in affiliated chain.
     int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
@@ -458,21 +392,12 @@
     String mCallingPackage;
     String mCallingFeatureId;
 
-    private final Rect mTmpStableBounds = new Rect();
-    private final Rect mTmpNonDecorBounds = new Rect();
-    private final Rect mTmpBounds = new Rect();
-    private final Rect mTmpInsets = new Rect();
-    private final Rect mTmpFullBounds = new Rect();
     private static final Rect sTmpBounds = new Rect();
 
     // Last non-fullscreen bounds the task was launched in or resized to.
     // The information is persisted and used to determine the appropriate root task to launch the
     // task into on restore.
     Rect mLastNonFullscreenBounds = null;
-    // Minimal width and height of this task when it's resizeable. -1 means it should use the
-    // default minimal width/height.
-    int mMinWidth;
-    int mMinHeight;
 
     // The surface transition of the target when recents animation is finished.
     // This is originally introduced to carry out the current surface control position and window
@@ -497,10 +422,6 @@
     /** Used by fillTaskInfo */
     final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
 
-    final ActivityTaskManagerService mAtmService;
-    final ActivityTaskSupervisor mTaskSupervisor;
-    final RootWindowContainer mRootWindowContainer;
-
     /* Unique identifier for this task. */
     final int mTaskId;
     /* User for which this task was created. */
@@ -571,29 +492,6 @@
     /** ActivityRecords that are exiting, but still on screen for animations. */
     final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
 
-    /**
-     * When we are in the process of pausing an activity, before starting the
-     * next one, this variable holds the activity that is currently being paused.
-     *
-     * Only set at leaf tasks.
-     */
-    @Nullable
-    private ActivityRecord mPausingActivity = null;
-
-    /**
-     * This is the last activity that we put into the paused state.  This is
-     * used to determine if we need to do an activity transition while sleeping,
-     * when we normally hold the top activity paused.
-     */
-    ActivityRecord mLastPausedActivity = null;
-
-    /**
-     * Current activity that is resumed, or null if there is none.
-     * Only set at leaf tasks.
-     */
-    @Nullable
-    private ActivityRecord mResumedActivity = null;
-
     private boolean mForceShowForAllUsers;
 
     /** When set, will force the task to report as invisible. */
@@ -641,121 +539,6 @@
     }
 
     private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper();
-    private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
-            new EnsureActivitiesVisibleHelper(this);
-    private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
-            new EnsureVisibleActivitiesConfigHelper();
-    private class EnsureVisibleActivitiesConfigHelper {
-        private boolean mUpdateConfig;
-        private boolean mPreserveWindow;
-        private boolean mBehindFullscreen;
-
-        void reset(boolean preserveWindow) {
-            mPreserveWindow = preserveWindow;
-            mUpdateConfig = false;
-            mBehindFullscreen = false;
-        }
-
-        void process(ActivityRecord start, boolean preserveWindow) {
-            if (start == null || !start.mVisibleRequested) {
-                return;
-            }
-            reset(preserveWindow);
-
-            final PooledFunction f = PooledLambda.obtainFunction(
-                    EnsureVisibleActivitiesConfigHelper::processActivity, this,
-                    PooledLambda.__(ActivityRecord.class));
-            forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/);
-            f.recycle();
-
-            if (mUpdateConfig) {
-                // Ensure the resumed state of the focus activity if we updated the configuration of
-                // any activity.
-                mRootWindowContainer.resumeFocusedTasksTopActivities();
-            }
-        }
-
-        boolean processActivity(ActivityRecord r) {
-            mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
-            mBehindFullscreen |= r.occludesParent();
-            return mBehindFullscreen;
-        }
-    }
-
-    private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper =
-            new CheckBehindFullscreenActivityHelper();
-    private class CheckBehindFullscreenActivityHelper {
-        private boolean mAboveTop;
-        private boolean mBehindFullscreenActivity;
-        private ActivityRecord mToCheck;
-        private Consumer<ActivityRecord> mHandleBehindFullscreenActivity;
-        private boolean mHandlingOccluded;
-
-        private void reset(ActivityRecord toCheck,
-                Consumer<ActivityRecord> handleBehindFullscreenActivity) {
-            mToCheck = toCheck;
-            mHandleBehindFullscreenActivity = handleBehindFullscreenActivity;
-            mAboveTop = true;
-            mBehindFullscreenActivity = false;
-
-            if (!shouldBeVisible(null)) {
-                // The root task is not visible, so no activity in it should be displaying a
-                // starting window. Mark all activities below top and behind fullscreen.
-                mAboveTop = false;
-                mBehindFullscreenActivity = true;
-            }
-
-            mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null;
-        }
-
-        boolean process(ActivityRecord toCheck,
-                Consumer<ActivityRecord> handleBehindFullscreenActivity) {
-            reset(toCheck, handleBehindFullscreenActivity);
-
-            if (!mHandlingOccluded && mBehindFullscreenActivity) {
-                return true;
-            }
-
-            final ActivityRecord topActivity = topRunningActivity();
-            final PooledFunction f = PooledLambda.obtainFunction(
-                    CheckBehindFullscreenActivityHelper::processActivity, this,
-                    PooledLambda.__(ActivityRecord.class), topActivity);
-            forAllActivities(f);
-            f.recycle();
-
-            return mBehindFullscreenActivity;
-        }
-
-        /** Returns {@code true} to stop the outer loop and indicate the result is computed. */
-        private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) {
-            if (mAboveTop) {
-                if (r == topActivity) {
-                    if (r == mToCheck) {
-                        // It is the top activity in a visible root task.
-                        mBehindFullscreenActivity = false;
-                        return true;
-                    }
-                    mAboveTop = false;
-                }
-                mBehindFullscreenActivity |= r.occludesParent();
-                return false;
-            }
-
-            if (mHandlingOccluded) {
-                // Iterating through all occluded activities.
-                if (mBehindFullscreenActivity) {
-                    mHandleBehindFullscreenActivity.accept(r);
-                }
-            } else if (r == mToCheck) {
-                return true;
-            } else if (mBehindFullscreenActivity) {
-                // It is occluded before {@param toCheck} is found.
-                return true;
-            }
-            mBehindFullscreenActivity |= r.occludesParent();
-            return false;
-        }
-    }
 
     private final FindRootHelper mFindRootHelper = new FindRootHelper();
     private class FindRootHelper {
@@ -819,18 +602,6 @@
      */
     private boolean mForceNotOrganized;
 
-    /**
-     * This task was created by the task organizer which has the following implementations.
-     * <ul>
-     *     <lis>The task won't be removed when it is empty. Removal has to be an explicit request
-     *     from the task organizer.</li>
-     *     <li>Unlike other non-root tasks, it's direct children are visible to the task
-     *     organizer for ordering purposes.</li>
-     * </ul>
-     */
-    @VisibleForTesting
-    boolean mCreatedByOrganizer;
-
     // Tracking cookie for the creation of this task.
     IBinder mLaunchCookie;
 
@@ -858,11 +629,8 @@
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
             boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
             boolean _removeWithTaskOrganizer) {
-        super(atmService.mWindowManager);
+        super(atmService, _createdByOrganizer);
 
-        mAtmService = atmService;
-        mTaskSupervisor = atmService.mTaskSupervisor;
-        mRootWindowContainer = mAtmService.mRootWindowContainer;
         mTaskId = _taskId;
         mUserId = _userId;
         mResizeMode = resizeMode;
@@ -913,7 +681,6 @@
         mHandler = new ActivityTaskHandler(mTaskSupervisor.mLooper);
         mCurrentUser = mAtmService.mAmInternal.getCurrentUserId();
 
-        mCreatedByOrganizer = _createdByOrganizer;
         mLaunchCookie = _launchCookie;
         mDeferTaskAppear = _deferTaskAppear;
         mRemoveWithTaskOrganizer = _removeWithTaskOrganizer;
@@ -1472,64 +1239,80 @@
         }
     }
 
-    void cleanUpActivityReferences(ActivityRecord r) {
-        // mPausingActivity is set at leaf task
-        if (mPausingActivity != null && mPausingActivity == r) {
-            mPausingActivity = null;
+    /** Returns the currently topmost resumed activity. */
+    @Nullable
+    ActivityRecord getTopResumedActivity() {
+        if (!isLeafTask()) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                ActivityRecord resumedActivity = mChildren.get(i).asTask().getTopResumedActivity();
+                if (resumedActivity != null) {
+                    return resumedActivity;
+                }
+            }
         }
 
-        if (mResumedActivity != null && mResumedActivity == r) {
-            setResumedActivity(null, "cleanUpActivityReferences");
+        final ActivityRecord taskResumedActivity = getResumedActivity();
+        ActivityRecord topResumedActivity = null;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskFragment() != null) {
+                final ActivityRecord[] resumedActivity = new ActivityRecord[1];
+                child.asTaskFragment().forAllLeafTaskFragments(fragment -> {
+                    if (fragment.getResumedActivity() != null) {
+                        resumedActivity[0] = fragment.getResumedActivity();
+                        return true;
+                    }
+                    return false;
+                });
+                topResumedActivity = resumedActivity[0];
+            } else if (taskResumedActivity != null
+                    && child.asActivityRecord() == taskResumedActivity) {
+                topResumedActivity = taskResumedActivity;
+            }
+            if (topResumedActivity != null) {
+                return topResumedActivity;
+            }
         }
-
-        final WindowContainer parent = getParent();
-        if (parent != null && parent.asTask() != null) {
-            parent.asTask().cleanUpActivityReferences(r);
-            return;
-        }
-        r.removeTimeouts();
-        mExitingActivities.remove(r);
-    }
-
-    /** @return the currently resumed activity. */
-    ActivityRecord getResumedActivity() {
-        if (isLeafTask()) {
-            return mResumedActivity;
-        }
-
-        final Task task = getTask(t -> t.mResumedActivity != null, true /* traverseTopToBottom */);
-        return task != null ? task.mResumedActivity : null;
-    }
-
-    @VisibleForTesting
-    void setPausingActivity(ActivityRecord pausing) {
-        mPausingActivity = pausing;
+        return null;
     }
 
     /**
-     * @return the currently pausing activity of this task or the topmost pausing activity of the
-     * child tasks
+     * Returns the currently topmost pausing activity.
      */
-    ActivityRecord getPausingActivity() {
-        if (isLeafTask()) {
-            return mPausingActivity;
+    @Nullable
+    ActivityRecord getTopPausingActivity() {
+        if (!isLeafTask()) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                ActivityRecord pausingActivity = mChildren.get(i).asTask().getTopPausingActivity();
+                if (pausingActivity != null) {
+                    return pausingActivity;
+                }
+            }
         }
 
-        final Task task = getTask(t -> t.mPausingActivity != null, true /* traverseTopToBottom */);
-        return task != null ? task.mPausingActivity : null;
-    }
-
-    void setResumedActivity(ActivityRecord r, String reason) {
-        warnForNonLeafTask("setResumedActivity");
-        if (mResumedActivity == r) {
-            return;
+        final ActivityRecord taskPausingActivity = getPausingActivity();
+        ActivityRecord topPausingActivity = null;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskFragment() != null) {
+                final ActivityRecord[] pausingActivity = new ActivityRecord[1];
+                child.asTaskFragment().forAllLeafTaskFragments(fragment -> {
+                    if (fragment.getPausingActivity() != null) {
+                        pausingActivity[0] = fragment.getPausingActivity();
+                        return true;
+                    }
+                    return false;
+                });
+                topPausingActivity = pausingActivity[0];
+            } else if (taskPausingActivity != null
+                    && child.asActivityRecord() == taskPausingActivity) {
+                topPausingActivity = taskPausingActivity;
+            }
+            if (topPausingActivity != null) {
+                return topPausingActivity;
+            }
         }
-
-        if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
-                "setResumedActivity task:" + this + " + from: "
-                + mResumedActivity + " to:" + r + " reason:" + reason);
-        mResumedActivity = r;
-        mTaskSupervisor.updateTopResumedActivityIfNeeded();
+        return null;
     }
 
     void updateTaskMovement(boolean toTop, int position) {
@@ -1568,11 +1351,6 @@
                 mTaskId, mUserId);
     }
 
-    void setAdjacentTask(Task adjacent) {
-        mAdjacentTask = adjacent;
-        adjacent.mAdjacentTask = this;
-    }
-
     void setTaskToAffiliateWith(Task taskToAffiliateWith) {
         closeRecentsChain();
         mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
@@ -1681,22 +1459,7 @@
     }
 
     @Override
-    public int getActivityType() {
-        final int applicationType = super.getActivityType();
-        if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
-            return applicationType;
-        }
-        return getTopChild().getActivityType();
-    }
-
-    @Override
     void addChild(WindowContainer child, int index) {
-        // If this task had any child before we added this one.
-        boolean hadChild = hasChild();
-        // getActivityType() looks at the top child, so we need to read the type before adding
-        // a new child in case the new child is on top and UNDEFINED.
-        final int activityType = getActivityType();
-
         index = getAdjustedChildPosition(child, index);
         super.addChild(child, index);
 
@@ -1711,11 +1474,11 @@
         // Make sure the list of display UID allowlists is updated
         // now that this record is in a new task.
         mRootWindowContainer.updateUIDsPresentOnDisplay();
+    }
 
-        final ActivityRecord r = child.asActivityRecord();
-        if (r == null) return;
-
-        r.inHistory = true;
+    /** Called when an {@link ActivityRecord} is added as a descendant */
+    void onDescendantActivityAdded(boolean hadChild, int activityType, ActivityRecord r) {
+        warnForNonLeafTask("onDescendantActivityAdded");
 
         // Only set this based on the first activity
         if (!hadChild) {
@@ -1742,10 +1505,6 @@
         updateEffectiveIntent();
     }
 
-    void addChild(ActivityRecord r) {
-        addChild(r, Integer.MAX_VALUE /* add on top */);
-    }
-
     @Override
     void removeChild(WindowContainer child) {
         removeChild(child, "removeChild");
@@ -1991,32 +1750,6 @@
                 && supportsMultiWindowInDisplayArea(tda);
     }
 
-    boolean supportsMultiWindow() {
-        return supportsMultiWindowInDisplayArea(getDisplayArea());
-    }
-
-    /**
-     * @return whether this task supports multi-window if it is in the given
-     *         {@link TaskDisplayArea}.
-     */
-    boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) {
-        if (!mAtmService.mSupportsMultiWindow) {
-            return false;
-        }
-        if (tda == null) {
-            Slog.w(TAG_TASKS, "Can't find TaskDisplayArea to determine support for multi"
-                    + " window. Task id=" + mTaskId + " attached=" + isAttached());
-            return false;
-        }
-
-        if (!isResizeable() && !tda.supportsNonResizableMultiWindow()) {
-            // Not support non-resizable in multi window.
-            return false;
-        }
-
-        return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight);
-    }
-
     /**
      * Check whether this task can be launched on the specified display.
      *
@@ -2152,60 +1885,6 @@
         }
     }
 
-    void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
-            @NonNull Configuration parentConfig) {
-        int minWidth = mMinWidth;
-        int minHeight = mMinHeight;
-        // If the task has no requested minimal size, we'd like to enforce a minimal size
-        // so that the user can not render the task too small to manipulate. We don't need
-        // to do this for the root pinned task as the bounds are controlled by the system.
-        if (!inPinnedWindowingMode()) {
-            final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
-            final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
-            final int defaultMinSize = (int) (defaultMinSizeDp * density);
-
-            if (minWidth == INVALID_MIN_SIZE) {
-                minWidth = defaultMinSize;
-            }
-            if (minHeight == INVALID_MIN_SIZE) {
-                minHeight = defaultMinSize;
-            }
-        }
-        if (bounds.isEmpty()) {
-            // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
-            // do, we can just skip.
-            final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
-            if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
-                return;
-            }
-            bounds.set(parentBounds);
-        }
-        final boolean adjustWidth = minWidth > bounds.width();
-        final boolean adjustHeight = minHeight > bounds.height();
-        if (!(adjustWidth || adjustHeight)) {
-            return;
-        }
-
-        if (adjustWidth) {
-            if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
-                bounds.left = bounds.right - minWidth;
-            } else {
-                // Either left bounds match, or neither match, or the previous bounds were
-                // fullscreen and we default to keeping left.
-                bounds.right = bounds.left + minWidth;
-            }
-        }
-        if (adjustHeight) {
-            if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
-                bounds.top = bounds.bottom - minHeight;
-            } else {
-                // Either top bounds match, or neither match, or the previous bounds were
-                // fullscreen and we default to keeping top.
-                bounds.bottom = bounds.top + minHeight;
-            }
-        }
-    }
-
     void setLastNonFullscreenBounds(Rect bounds) {
         if (mLastNonFullscreenBounds == null) {
             mLastNonFullscreenBounds = new Rect(bounds);
@@ -2214,32 +1893,6 @@
         }
     }
 
-    /**
-     * This should be called when an child activity changes state. This should only
-     * be called from
-     * {@link ActivityRecord#setState(ActivityState, String)} .
-     * @param record The {@link ActivityRecord} whose state has changed.
-     * @param state The new state.
-     * @param reason The reason for the change.
-     */
-    void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
-        warnForNonLeafTask("onActivityStateChanged");
-        if (record == mResumedActivity && state != RESUMED) {
-            setResumedActivity(null, reason + " - onActivityStateChanged");
-        }
-
-        if (state == RESUMED) {
-            if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
-                Slog.v(TAG_ROOT_TASK, "set resumed activity to:" + record + " reason:" + reason);
-            }
-            setResumedActivity(record, reason + " - onActivityStateChanged");
-            if (record == mRootWindowContainer.getTopResumedActivity()) {
-                mAtmService.setResumedActivityUncheckLocked(record, reason);
-            }
-            mTaskSupervisor.mRecentTasks.add(record.getTask());
-        }
-    }
-
     private void onConfigurationChangedInner(Configuration newParentConfig) {
         // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
         // restore the last recorded non-fullscreen bounds.
@@ -2532,400 +2185,6 @@
         mTaskSupervisor.mLaunchParamsPersister.saveTask(this, display);
     }
 
-    /**
-     * Adjust bounds to stay within root task bounds.
-     *
-     * Since bounds might be outside of root task bounds, this method tries to move the bounds in
-     * a way that keep them unchanged, but be contained within the root task bounds.
-     *
-     * @param bounds Bounds to be adjusted.
-     * @param rootTaskBounds Bounds within which the other bounds should remain.
-     * @param overlapPxX The amount of px required to be visible in the X dimension.
-     * @param overlapPxY The amount of px required to be visible in the Y dimension.
-     */
-    private static void fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX,
-            int overlapPxY) {
-        if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) {
-            return;
-        }
-
-        // For each side of the parent (eg. left), check if the opposing side of the window (eg.
-        // right) is at least overlap pixels away. If less, offset the window by that difference.
-        int horizontalDiff = 0;
-        // If window is smaller than overlap, use it's smallest dimension instead
-        int overlapLR = Math.min(overlapPxX, bounds.width());
-        if (bounds.right < (rootTaskBounds.left + overlapLR)) {
-            horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left);
-        } else if (bounds.left > (rootTaskBounds.right - overlapLR)) {
-            horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left));
-        }
-        int verticalDiff = 0;
-        int overlapTB = Math.min(overlapPxY, bounds.width());
-        if (bounds.bottom < (rootTaskBounds.top + overlapTB)) {
-            verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top);
-        } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) {
-            verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top));
-        }
-        bounds.offset(horizontalDiff, verticalDiff);
-    }
-
-    /**
-     * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
-     * intersectBounds on a side, then the respective side will not be intersected.
-     *
-     * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
-     * inset on that side is no-longer applicable. This scenario happens when a task's minimal
-     * bounds are larger than the provided parent/display bounds.
-     *
-     * @param inOutBounds the bounds to intersect.
-     * @param intersectBounds the bounds to intersect with.
-     * @param intersectInsets insets to apply to intersectBounds before intersecting.
-     */
-    static void intersectWithInsetsIfFits(
-            Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
-        if (inOutBounds.right <= intersectBounds.right) {
-            inOutBounds.right =
-                    Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
-        }
-        if (inOutBounds.bottom <= intersectBounds.bottom) {
-            inOutBounds.bottom =
-                    Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
-        }
-        if (inOutBounds.left >= intersectBounds.left) {
-            inOutBounds.left =
-                    Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
-        }
-        if (inOutBounds.top >= intersectBounds.top) {
-            inOutBounds.top =
-                    Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
-        }
-    }
-
-    /**
-     * Gets bounds with non-decor and stable insets applied respectively.
-     *
-     * If bounds overhangs the display, those edges will not get insets. See
-     * {@link #intersectWithInsetsIfFits}
-     *
-     * @param outNonDecorBounds where to place bounds with non-decor insets applied.
-     * @param outStableBounds where to place bounds with stable insets applied.
-     * @param bounds the bounds to inset.
-     */
-    private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
-            DisplayInfo displayInfo) {
-        outNonDecorBounds.set(bounds);
-        outStableBounds.set(bounds);
-        final Task rootTask = getRootTask();
-        if (rootTask == null || rootTask.mDisplayContent == null) {
-            return;
-        }
-        mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-
-        final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
-        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
-                displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
-        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
-
-        policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
-        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
-    }
-
-    /**
-     * Forces the app bounds related configuration can be computed by
-     * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
-     * ActivityRecord.CompatDisplayInsets)}.
-     */
-    private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
-        final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
-        if (appBounds != null) {
-            appBounds.setEmpty();
-        }
-        inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
-        inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
-    }
-
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
-        if (overrideDisplayInfo != null) {
-            // Make sure the screen related configs can be computed by the provided display info.
-            inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
-            invalidateAppBoundsConfig(inOutConfig);
-        }
-        computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
-                null /* compatInsets */);
-    }
-
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig) {
-        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
-                null /* compatInsets */);
-    }
-
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig,
-            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
-        if (compatInsets != null) {
-            // Make sure the app bounds can be computed by the compat insets.
-            invalidateAppBoundsConfig(inOutConfig);
-        }
-        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
-                compatInsets);
-    }
-
-    /**
-     * Calculates configuration values used by the client to get resources. This should be run
-     * using app-facing bounds (bounds unmodified by animations or transient interactions).
-     *
-     * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
-     * configuring an "inherit-bounds" window which means that all configuration settings would
-     * just be inherited from the parent configuration.
-     **/
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
-            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
-        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
-        }
-
-        float density = inOutConfig.densityDpi;
-        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
-            density = parentConfig.densityDpi;
-        }
-        density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
-
-        // The bounds may have been overridden at this level. If the parent cannot cover these
-        // bounds, the configuration is still computed according to the override bounds.
-        final boolean insideParentBounds;
-
-        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
-        final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
-        if (resolvedBounds == null || resolvedBounds.isEmpty()) {
-            mTmpFullBounds.set(parentBounds);
-            insideParentBounds = true;
-        } else {
-            mTmpFullBounds.set(resolvedBounds);
-            insideParentBounds = parentBounds.contains(resolvedBounds);
-        }
-
-        // Non-null compatibility insets means the activity prefers to keep its original size, so
-        // out bounds doesn't need to be restricted by the parent or current display
-        final boolean customContainerPolicy = compatInsets != null;
-
-        Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
-        if (outAppBounds == null || outAppBounds.isEmpty()) {
-            // App-bounds hasn't been overridden, so calculate a value for it.
-            inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
-            outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
-
-            if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
-                final Rect containingAppBounds;
-                if (insideParentBounds) {
-                    containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
-                } else {
-                    // Restrict appBounds to display non-decor rather than parent because the
-                    // override bounds are beyond the parent. Otherwise, it won't match the
-                    // overridden bounds.
-                    final TaskDisplayArea displayArea = getDisplayArea();
-                    containingAppBounds = displayArea != null
-                            ? displayArea.getWindowConfiguration().getAppBounds() : null;
-                }
-                if (containingAppBounds != null && !containingAppBounds.isEmpty()) {
-                    outAppBounds.intersect(containingAppBounds);
-                }
-            }
-        }
-
-        if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
-                || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-            if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
-                mTmpNonDecorBounds.set(mTmpFullBounds);
-                mTmpStableBounds.set(mTmpFullBounds);
-            } else if (!customContainerPolicy
-                    && (overrideDisplayInfo != null || getDisplayContent() != null)) {
-                final DisplayInfo di = overrideDisplayInfo != null
-                        ? overrideDisplayInfo
-                        : getDisplayContent().getDisplayInfo();
-
-                // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
-                // area, i.e. the screen area without the system bars.
-                // The non decor inset are areas that could never be removed in Honeycomb. See
-                // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
-                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
-            } else {
-                // Apply the given non-decor and stable insets to calculate the corresponding bounds
-                // for screen size of configuration.
-                int rotation = inOutConfig.windowConfiguration.getRotation();
-                if (rotation == ROTATION_UNDEFINED) {
-                    rotation = parentConfig.windowConfiguration.getRotation();
-                }
-                if (rotation != ROTATION_UNDEFINED && customContainerPolicy) {
-                    mTmpNonDecorBounds.set(mTmpFullBounds);
-                    mTmpStableBounds.set(mTmpFullBounds);
-                    compatInsets.getBoundsByRotation(mTmpBounds, rotation);
-                    intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
-                            compatInsets.mNonDecorInsets[rotation]);
-                    intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
-                            compatInsets.mStableInsets[rotation]);
-                    outAppBounds.set(mTmpNonDecorBounds);
-                } else {
-                    // Set to app bounds because it excludes decor insets.
-                    mTmpNonDecorBounds.set(outAppBounds);
-                    mTmpStableBounds.set(outAppBounds);
-                }
-            }
-
-            if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
-                final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
-                inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
-                        ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
-                        : overrideScreenWidthDp;
-            }
-            if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-                final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
-                inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
-                        ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
-                        : overrideScreenHeightDp;
-            }
-
-            if (inOutConfig.smallestScreenWidthDp
-                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
-                if (WindowConfiguration.isFloating(windowingMode)) {
-                    // For floating tasks, calculate the smallest width from the bounds of the task
-                    inOutConfig.smallestScreenWidthDp = (int) (
-                            Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
-                }
-                // otherwise, it will just inherit
-            }
-        }
-
-        if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
-            inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
-                    ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
-        }
-        if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
-            // For calculating screen layout, we need to use the non-decor inset screen area for the
-            // calculation for compatibility reasons, i.e. screen area without system bars that
-            // could never go away in Honeycomb.
-            int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
-            int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
-            // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
-            // undefined so it can't be used.
-            if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
-                compatScreenWidthDp = inOutConfig.screenWidthDp;
-            }
-            if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-                compatScreenHeightDp = inOutConfig.screenHeightDp;
-            }
-            // Reducing the screen layout starting from its parent config.
-            inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
-                    compatScreenWidthDp, compatScreenHeightDp);
-        }
-    }
-
-    /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */
-    static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp,
-            int screenHeightDp) {
-        sourceScreenLayout = sourceScreenLayout
-                & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
-        final int longSize = Math.max(screenWidthDp, screenHeightDp);
-        final int shortSize = Math.min(screenWidthDp, screenHeightDp);
-        return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
-    }
-
-    @Override
-    void resolveOverrideConfiguration(Configuration newParentConfig) {
-        mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
-        super.resolveOverrideConfiguration(newParentConfig);
-
-        int windowingMode =
-                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
-        final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
-
-        // Resolve override windowing mode to fullscreen for home task (even on freeform
-        // display), or split-screen if in split-screen mode.
-        if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
-            windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode)
-                    ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN;
-            getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
-        }
-
-        // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in
-        // pinned windowing mode.
-        if (!supportsMultiWindow()) {
-            final int candidateWindowingMode =
-                    windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
-            if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
-                    && candidateWindowingMode != WINDOWING_MODE_PINNED) {
-                getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
-                        WINDOWING_MODE_FULLSCREEN);
-            }
-        }
-
-        if (isLeafTask()) {
-            resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */);
-        }
-        computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
-    }
-
-    private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
-            Rect previousBounds) {
-
-        int windowingMode =
-                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
-        }
-        // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old
-        // mode that may cause the bounds to be miscalculated, e.g. letterboxed.
-        getConfiguration().windowConfiguration.setWindowingMode(windowingMode);
-        Rect outOverrideBounds =
-                getResolvedOverrideConfiguration().windowConfiguration.getBounds();
-
-        if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            // Use empty bounds to indicate "fill parent".
-            outOverrideBounds.setEmpty();
-            // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
-            // the parent or display is smaller than the size, the content may be cropped.
-            return;
-        }
-
-        adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
-        if (windowingMode == WINDOWING_MODE_FREEFORM) {
-            computeFreeformBounds(outOverrideBounds, newParentConfig);
-            return;
-        }
-    }
-
-    /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
-    private void computeFreeformBounds(@NonNull Rect outBounds,
-            @NonNull Configuration newParentConfig) {
-        // by policy, make sure the window remains within parent somewhere
-        final float density =
-                ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
-        final Rect parentBounds =
-                new Rect(newParentConfig.windowConfiguration.getBounds());
-        final DisplayContent display = getDisplayContent();
-        if (display != null) {
-            // If a freeform window moves below system bar, there is no way to move it again
-            // by touch. Because its caption is covered by system bar. So we exclude them
-            // from root task bounds. and then caption will be shown inside stable area.
-            final Rect stableBounds = new Rect();
-            display.getStableRect(stableBounds);
-            parentBounds.intersect(stableBounds);
-        }
-
-        fitWithinBounds(outBounds, parentBounds,
-                (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
-                (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
-
-        // Prevent to overlap caption with stable insets.
-        final int offsetTop = parentBounds.top - outBounds.top;
-        if (offsetTop > 0) {
-            outBounds.offset(0, offsetTop);
-        }
-    }
-
     Rect updateOverrideConfigurationFromLaunchBounds() {
         // If the task is controlled by another organized task, do not set override
         // configurations and let its parent (organized task) to control it;
@@ -2974,22 +2233,14 @@
         }
     }
 
-    int getDisplayId() {
-        final DisplayContent dc = getDisplayContent();
-        return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
-    }
-
     /** @return Id of root task. */
     int getRootTaskId() {
         return getRootTask().mTaskId;
     }
 
+    @Nullable
     Task getRootTask() {
-        final WindowContainer parent = getParent();
-        if (parent == null) return this;
-
-        final Task parentTask = parent.asTask();
-        return parentTask == null ? this : parentTask.getRootTask();
+        return getRootTaskFragment().asTask();
     }
 
     /** @return the first organized task. */
@@ -3104,12 +2355,12 @@
         // and focused application if needed.
         focusableTask.moveToFront(myReason);
         // Top display focused root task is changed, update top resumed activity if needed.
-        if (rootTask.getResumedActivity() != null) {
+        if (rootTask.getTopResumedActivity() != null) {
             mTaskSupervisor.updateTopResumedActivityIfNeeded();
             // Set focused app directly because if the next focused activity is already resumed
             // (e.g. the next top activity is on a different display), there won't have activity
             // state change to update it.
-            mAtmService.setResumedActivityUncheckLocked(rootTask.getResumedActivity(), reason);
+            mAtmService.setResumedActivityUncheckLocked(rootTask.getTopResumedActivity(), reason);
         }
         return rootTask;
     }
@@ -3158,17 +2409,16 @@
 
         // Figure-out min/max possible position depending on if child can show for current user.
         int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0;
-        int maxPosition = (canShowChild) ? size - 1 : computeMaxUserPosition(size - 1);
-        if (!hasChild(wc)) {
-            // Increase the maxPosition because children size will grow once wc is added.
-            ++maxPosition;
+        int maxPosition = minPosition;
+        if (size > 0) {
+            maxPosition = (canShowChild) ? size - 1 : computeMaxUserPosition(size - 1);
         }
 
         // Factor in always-on-top children in max possible position.
         if (!wc.isAlwaysOnTop()) {
             // We want to place all non-always-on-top containers below always-on-top ones.
             while (maxPosition > minPosition) {
-                if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break;
+                if (!mChildren.get(maxPosition).isAlwaysOnTop()) break;
                 --maxPosition;
             }
         }
@@ -3179,6 +2429,12 @@
         } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) {
             return POSITION_TOP;
         }
+
+        // Increase the maxPosition because children size will grow once wc is added.
+        if (!hasChild(wc)) {
+            ++maxPosition;
+        }
+
         // Reset position based on minimum/maximum possible positions.
         return Math.min(Math.max(suggestedPosition, minPosition), maxPosition);
     }
@@ -3560,18 +2816,6 @@
         mForceShowForAllUsers = forceShowForAllUsers;
     }
 
-    @Override
-    public boolean isAttached() {
-        final TaskDisplayArea taskDisplayArea = getDisplayArea();
-        return taskDisplayArea != null && !taskDisplayArea.isRemoved();
-    }
-
-    @Override
-    @Nullable
-    TaskDisplayArea getDisplayArea() {
-        return (TaskDisplayArea) super.getDisplayArea();
-    }
-
     /**
      * When we are in a floating root task (Freeform, Pinned, ...) we calculate
      * insets differently. However if we are animating to the fullscreen root task
@@ -3582,45 +2826,6 @@
         return getWindowConfiguration().tasksAreFloating() && !mPreserveNonFloatingState;
     }
 
-    /**
-     * Returns true if the root task is translucent and can have other contents visible behind it if
-     * needed. A root task is considered translucent if it don't contain a visible or
-     * starting (about to be visible) activity that is fullscreen (opaque).
-     * @param starting The currently starting activity or null if there is none.
-     */
-    @VisibleForTesting
-    boolean isTranslucent(ActivityRecord starting) {
-        if (!isAttached() || isForceHidden()) {
-            return true;
-        }
-        final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity,
-                PooledLambda.__(ActivityRecord.class), starting);
-        final ActivityRecord opaque = getActivity(p);
-        p.recycle();
-        return opaque == null;
-    }
-
-    private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
-        if (r.finishing) {
-            // We don't factor in finishing activities when determining translucency since
-            // they will be gone soon.
-            return false;
-        }
-
-        if (!r.visibleIgnoringKeyguard && r != starting) {
-            // Also ignore invisible activities that are not the currently starting
-            // activity (about to be visible).
-            return false;
-        }
-
-        if (r.occludesParent()) {
-            // Root task isn't translucent if it has at least one fullscreen activity
-            // that is visible.
-            return true;
-        }
-        return false;
-    }
-
     /** Returns the top-most activity that occludes the given one, or {@code null} if none. */
     @Nullable
     ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
@@ -3714,19 +2919,6 @@
         return activity != null ? activity.findMainWindow() : null;
     }
 
-    ActivityRecord topRunningActivity() {
-        return topRunningActivity(false /* focusableOnly */);
-    }
-
-    ActivityRecord topRunningActivity(boolean focusableOnly) {
-        // Split into 2 to avoid object creation due to variable capture.
-        if (focusableOnly) {
-            return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
-        } else {
-            return getActivity(ActivityRecord::canBeTopRunning);
-        }
-    }
-
     ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed
                 , PooledLambda.__(ActivityRecord.class), notTop);
@@ -3781,12 +2973,6 @@
         });
     }
 
-    boolean isTopActivityFocusable() {
-        final ActivityRecord r = topRunningActivity();
-        return r != null ? r.isFocusable()
-                : (isFocusable() && getWindowConfiguration().canReceiveKeys());
-    }
-
     boolean isFocusableAndVisible() {
         return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
     }
@@ -3902,6 +3088,41 @@
         return false;
     }
 
+    /** Iterates through all leaf task fragments and the leaf tasks. */
+    void forAllLeafTasksAndLeafTaskFragments(final Consumer<TaskFragment> callback,
+            boolean traverseTopToBottom) {
+        forAllLeafTasks(task -> {
+            if (task.isLeafTaskFragment()) {
+                callback.accept(task);
+                return;
+            }
+
+            // A leaf task that may contains both activities and task fragments.
+            boolean consumed = false;
+            if (traverseTopToBottom) {
+                for (int i = task.mChildren.size() - 1; i >= 0; --i) {
+                    final WindowContainer child = mChildren.get(i);
+                    if (child.asTaskFragment() != null) {
+                        child.forAllLeafTaskFragments(callback, traverseTopToBottom);
+                    } else if (child.asActivityRecord() != null && !consumed) {
+                        callback.accept(task);
+                        consumed = true;
+                    }
+                }
+            } else {
+                for (int i = 0; i < task.mChildren.size(); i++) {
+                    final WindowContainer child = mChildren.get(i);
+                    if (child.asTaskFragment() != null) {
+                        child.forAllLeafTaskFragments(callback, traverseTopToBottom);
+                    } else if (child.asActivityRecord() != null && !consumed) {
+                        callback.accept(task);
+                        consumed = true;
+                    }
+                }
+            }
+        }, traverseTopToBottom);
+    }
+
     @Override
     boolean forAllRootTasks(Function<Task, Boolean> callback, boolean traverseTopToBottom) {
         return isRootTask() ? callback.apply(this) : false;
@@ -4072,6 +3293,9 @@
         info.userId = isLeafTask() ? mUserId : mCurrentUser;
         info.taskId = mTaskId;
         info.displayId = getDisplayId();
+        if (tda != null) {
+            info.displayAreaFeatureId = tda.mFeatureId;
+        }
         info.isRunning = getTopNonFinishingActivity() != null;
         final Intent baseIntent = getBaseIntent();
         // Make a copy of base intent because this is like a snapshot info.
@@ -4133,6 +3357,7 @@
                 : INVALID_TASK_ID;
         info.isFocused = isFocused();
         info.isVisible = hasVisibleChildren();
+        info.isSleeping = shouldSleepActivities();
         ActivityRecord topRecord = getTopNonFinishingActivity();
         info.mTopActivityLocusId = topRecord != null ? topRecord.getLocusId() : null;
     }
@@ -4200,184 +3425,6 @@
         return this;
     }
 
-    /**
-     * Returns true if the task should be visible.
-     *
-     * @param starting The currently starting activity or null if there is none.
-     */
-    boolean shouldBeVisible(ActivityRecord starting) {
-        return getVisibility(starting) != TASK_VISIBILITY_INVISIBLE;
-    }
-
-    /**
-     * Returns true if the task should be visible.
-     *
-     * @param starting The currently starting activity or null if there is none.
-     */
-    @TaskVisibility
-    int getVisibility(ActivityRecord starting) {
-        if (!isAttached() || isForceHidden()) {
-            return TASK_VISIBILITY_INVISIBLE;
-        }
-
-        if (isTopActivityLaunchedBehind()) {
-            return TASK_VISIBILITY_VISIBLE;
-        }
-
-        boolean gotRootSplitScreenTask = false;
-        boolean gotOpaqueSplitScreenPrimary = false;
-        boolean gotOpaqueSplitScreenSecondary = false;
-        boolean gotTranslucentFullscreen = false;
-        boolean gotTranslucentSplitScreenPrimary = false;
-        boolean gotTranslucentSplitScreenSecondary = false;
-        boolean shouldBeVisible = true;
-
-        // This root task is only considered visible if all its parent root tasks are considered
-        // visible, so check the visibility of all ancestor root task first.
-        final WindowContainer parent = getParent();
-        if (parent.asTask() != null) {
-            final int parentVisibility = parent.asTask().getVisibility(starting);
-            if (parentVisibility == TASK_VISIBILITY_INVISIBLE) {
-                // Can't be visible if parent isn't visible
-                return TASK_VISIBILITY_INVISIBLE;
-            } else if (parentVisibility == TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
-                // Parent is behind a translucent container so the highest visibility this container
-                // can get is that.
-                gotTranslucentFullscreen = true;
-            }
-        }
-
-        final List<Task> adjacentTasks = new ArrayList<>();
-        final int windowingMode = getWindowingMode();
-        final boolean isAssistantType = isActivityTypeAssistant();
-        for (int i = parent.getChildCount() - 1; i >= 0; --i) {
-            final WindowContainer wc = parent.getChildAt(i);
-            final Task other = wc.asTask();
-            if (other == null) continue;
-
-            final boolean hasRunningActivities = other.topRunningActivity() != null;
-            if (other == this) {
-                // Should be visible if there is no other stack occluding it, unless it doesn't
-                // have any running activities, not starting one and not home stack.
-                shouldBeVisible = hasRunningActivities || isInTask(starting) != null
-                        || isActivityTypeHome();
-                break;
-            }
-
-            if (!hasRunningActivities) {
-                continue;
-            }
-
-            final int otherWindowingMode = other.getWindowingMode();
-
-            if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
-                if (other.isTranslucent(starting)) {
-                    // Can be visible behind a translucent fullscreen stack.
-                    gotTranslucentFullscreen = true;
-                    continue;
-                }
-                return TASK_VISIBILITY_INVISIBLE;
-            } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW
-                    && other.matchParentBounds()) {
-                if (other.isTranslucent(starting)) {
-                    // Can be visible behind a translucent task.
-                    gotTranslucentFullscreen = true;
-                    continue;
-                }
-                // Multi-window task that matches parent bounds would occlude other children.
-                return TASK_VISIBILITY_INVISIBLE;
-            } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                    && !gotOpaqueSplitScreenPrimary) {
-                gotRootSplitScreenTask = true;
-                gotTranslucentSplitScreenPrimary = other.isTranslucent(starting);
-                gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary;
-                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                        && gotOpaqueSplitScreenPrimary) {
-                    // Can not be visible behind another opaque stack in split-screen-primary mode.
-                    return TASK_VISIBILITY_INVISIBLE;
-                }
-            } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                    && !gotOpaqueSplitScreenSecondary) {
-                gotRootSplitScreenTask = true;
-                gotTranslucentSplitScreenSecondary = other.isTranslucent(starting);
-                gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary;
-                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                        && gotOpaqueSplitScreenSecondary) {
-                    // Can not be visible behind another opaque stack in split-screen-secondary mode.
-                    return TASK_VISIBILITY_INVISIBLE;
-                }
-            }
-            if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
-                // Can not be visible if we are in split-screen windowing mode and both halves of
-                // the screen are opaque.
-                return TASK_VISIBILITY_INVISIBLE;
-            }
-            if (isAssistantType && gotRootSplitScreenTask) {
-                // Assistant stack can't be visible behind split-screen. In addition to this not
-                // making sense, it also works around an issue here we boost the z-order of the
-                // assistant window surfaces in window manager whenever it is visible.
-                return TASK_VISIBILITY_INVISIBLE;
-            }
-            if (other.mAdjacentTask != null) {
-                if (adjacentTasks.contains(other.mAdjacentTask)) {
-                    if (other.isTranslucent(starting)
-                            || other.mAdjacentTask.isTranslucent(starting)) {
-                        // Can be visible behind a translucent adjacent tasks.
-                        gotTranslucentFullscreen = true;
-                        continue;
-                    }
-                    // Can not be visible behind adjacent tasks.
-                    return TASK_VISIBILITY_INVISIBLE;
-                } else {
-                    adjacentTasks.add(other);
-                }
-            }
-        }
-
-        if (!shouldBeVisible) {
-            return TASK_VISIBILITY_INVISIBLE;
-        }
-
-        // Handle cases when there can be a translucent split-screen stack on top.
-        switch (windowingMode) {
-            case WINDOWING_MODE_FULLSCREEN:
-                if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
-                    // At least one of the split-screen stacks that covers this one is translucent.
-                    // When in split mode, home task will be reparented to the secondary split while
-                    // leaving tasks not supporting split below. Due to
-                    // TaskDisplayArea#assignRootTaskOrdering always adjusts home surface layer to
-                    // the bottom, this makes sure tasks not in split roots won't occlude home task
-                    // unexpectedly.
-                    return TASK_VISIBILITY_INVISIBLE;
-                }
-                break;
-            case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
-                if (gotTranslucentSplitScreenPrimary) {
-                    // Covered by translucent primary split-screen on top.
-                    return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
-                }
-                break;
-            case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
-                if (gotTranslucentSplitScreenSecondary) {
-                    // Covered by translucent secondary split-screen on top.
-                    return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
-                }
-                break;
-        }
-
-        // Lastly - check if there is a translucent fullscreen stack on top.
-        return gotTranslucentFullscreen ? TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
-                : TASK_VISIBILITY_VISIBLE;
-    }
-
-    private boolean isTopActivityLaunchedBehind() {
-        final ActivityRecord top = topRunningActivity();
-        if (top != null && top.mLaunchTaskBehind) {
-            return true;
-        }
-        return false;
-    }
-
     ActivityRecord isInTask(ActivityRecord r) {
         if (r == null) {
             return null;
@@ -4560,7 +3607,7 @@
             // Increment the total number of non-finishing activities
             numActivities++;
 
-            if (top == null || (top.isState(ActivityState.INITIALIZING))) {
+            if (top == null || (top.isState(INITIALIZING))) {
                 top = r;
                 // Reset the number of running activities until we hit the first non-initializing
                 // activity
@@ -5303,9 +4350,7 @@
         return super.isAlwaysOnTop();
     }
 
-    /**
-     * Returns whether this task is currently forced to be hidden for any reason.
-     */
+    @Override
     protected boolean isForceHidden() {
         return mForceHiddenFlags != 0;
     }
@@ -5592,19 +4637,6 @@
         r.completeResumeLocked();
     }
 
-    void awakeFromSleepingLocked() {
-        if (!isLeafTask()) {
-            forAllLeafTasks((task) -> task.awakeFromSleepingLocked(),
-                    true /* traverseTopToBottom */);
-            return;
-        }
-
-        if (mPausingActivity != null) {
-            Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause");
-            mPausingActivity.activityPaused(true);
-        }
-    }
-
     void checkReadyForSleep() {
         if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
             mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
@@ -5623,302 +4655,13 @@
      * the process of going to sleep (checkReadyForSleep will be called when that process finishes).
      */
     boolean goToSleepIfPossible(boolean shuttingDown) {
-        if (!isLeafTask()) {
-            final int[] sleepInProgress = {0};
-            forAllLeafTasks((t) -> {
-                if (!t.goToSleepIfPossible(shuttingDown)) {
-                    sleepInProgress[0]++;
-                }
-            }, true);
-            return sleepInProgress[0] == 0;
-        }
-
-        boolean shouldSleep = true;
-        if (mResumedActivity != null) {
-            // Still have something resumed; can't sleep until it is paused.
-            ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity);
-            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
-                    "Sleep => pause with userLeaving=false");
-
-            startPausingLocked(false /* userLeaving */, true /* uiSleeping */, null /* resuming */,
-                    "sleep");
-            shouldSleep = false ;
-        } else if (mPausingActivity != null) {
-            // Still waiting for something to pause; can't sleep yet.
-            ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity);
-            shouldSleep = false;
-        }
-
-        if (!shuttingDown) {
-            if (containsActivityFromRootTask(mTaskSupervisor.mStoppingActivities)) {
-                // Still need to tell some activities to stop; can't sleep yet.
-                ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities",
-                        mTaskSupervisor.mStoppingActivities.size());
-
-                mTaskSupervisor.scheduleIdle();
-                shouldSleep = false;
+        final int[] sleepInProgress = {0};
+        forAllLeafTasksAndLeafTaskFragments(taskFragment -> {
+            if (!taskFragment.sleepIfPossible(shuttingDown)) {
+                sleepInProgress[0]++;
             }
-        }
-
-        if (shouldSleep) {
-            ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                    !PRESERVE_WINDOWS);
-        }
-
-        return shouldSleep;
-    }
-
-    private boolean containsActivityFromRootTask(List<ActivityRecord> rs) {
-        for (ActivityRecord r : rs) {
-            if (r.getRootTask() == this) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    final boolean startPausingLocked(boolean uiSleeping, ActivityRecord resuming, String reason) {
-        return startPausingLocked(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
-    }
-
-    /**
-     * Start pausing the currently resumed activity.  It is an error to call this if there
-     * is already an activity being paused or there is no resumed activity.
-     *
-     * @param userLeaving True if this should result in an onUserLeaving to the current activity.
-     * @param uiSleeping True if this is happening with the user interface going to sleep (the
-     * screen turning off).
-     * @param resuming The activity we are currently trying to resume or null if this is not being
-     *                 called as part of resuming the top activity, so we shouldn't try to instigate
-     *                 a resume here if not null.
-     * @param reason The reason of pausing the activity.
-     * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
-     * it to tell us when it is done.
-     */
-    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
-            ActivityRecord resuming, String reason) {
-        if (!isLeafTask()) {
-            final int[] pausing = {0};
-            forAllLeafTasks((t) -> {
-                if (t.startPausingLocked(userLeaving, uiSleeping, resuming, reason)) {
-                    pausing[0]++;
-                }
-            }, true /* traverseTopToBottom */);
-            return pausing[0] > 0;
-        }
-
-        if (mPausingActivity != null) {
-            Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
-                    + " state=" + mPausingActivity.getState());
-            if (!shouldSleepActivities()) {
-                // Avoid recursion among check for sleep and complete pause during sleeping.
-                // Because activity will be paused immediately after resume, just let pause
-                // be completed by the order of activity paused from clients.
-                completePauseLocked(false, resuming);
-            }
-        }
-        ActivityRecord prev = mResumedActivity;
-
-        if (prev == null) {
-            if (resuming == null) {
-                Slog.wtf(TAG, "Trying to pause when nothing is resumed");
-                mRootWindowContainer.resumeFocusedTasksTopActivities();
-            }
-            return false;
-        }
-
-        if (prev == resuming) {
-            Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
-            return false;
-        }
-
-        ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
-        mPausingActivity = prev;
-        mLastPausedActivity = prev;
-        if (prev.isNoHistory() && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
-            mTaskSupervisor.mNoHistoryActivities.add(prev);
-        }
-        prev.setState(PAUSING, "startPausingLocked");
-        prev.getTask().touchActiveTime();
-
-        mAtmService.updateCpuStats();
-
-        boolean pauseImmediately = false;
-        boolean shouldAutoPip = false;
-        if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) {
-            // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
-            // activity to be paused, while at the same time resuming the new resume activity
-            // only if the previous activity can't go into Pip since we want to give Pip
-            // activities a chance to enter Pip before resuming the next activity.
-            final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState(
-                    "shouldResumeWhilePausing", userLeaving);
-            if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
-                shouldAutoPip = true;
-            } else if (!lastResumedCanPip) {
-                pauseImmediately = true;
-            } else {
-                // The previous activity may still enter PIP even though it did not allow auto-PIP.
-            }
-        }
-
-        boolean didAutoPip = false;
-        if (prev.attachedToProcess()) {
-            if (shouldAutoPip) {
-                ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
-                        + "directly: %s", prev);
-
-                didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
-                mPausingActivity = null;
-            } else {
-                ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
-                try {
-                    EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
-                            prev.shortComponentName, "userLeaving=" + userLeaving, reason);
-
-                    mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
-                            prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
-                                    prev.configChangeFlags, pauseImmediately));
-                } catch (Exception e) {
-                    // Ignore exception, if process died other code will cleanup.
-                    Slog.w(TAG, "Exception thrown during pause", e);
-                    mPausingActivity = null;
-                    mLastPausedActivity = null;
-                    mTaskSupervisor.mNoHistoryActivities.remove(prev);
-                }
-            }
-        } else {
-            mPausingActivity = null;
-            mLastPausedActivity = null;
-            mTaskSupervisor.mNoHistoryActivities.remove(prev);
-        }
-
-        // If we are not going to sleep, we want to ensure the device is
-        // awake until the next activity is started.
-        if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) {
-            mTaskSupervisor.acquireLaunchWakelock();
-        }
-
-        // If already entered PIP mode, no need to keep pausing.
-        if (mPausingActivity != null && !didAutoPip) {
-            // Have the window manager pause its key dispatching until the new
-            // activity has started.  If we're pausing the activity just because
-            // the screen is being turned off and the UI is sleeping, don't interrupt
-            // key dispatch; the same activity will pick it up again on wakeup.
-            if (!uiSleeping) {
-                prev.pauseKeyDispatchingLocked();
-            } else {
-                ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
-            }
-
-            if (pauseImmediately) {
-                // If the caller said they don't want to wait for the pause, then complete
-                // the pause now.
-                completePauseLocked(false, resuming);
-                return false;
-
-            } else {
-                prev.schedulePauseTimeout();
-                return true;
-            }
-
-        } else {
-            // This activity either failed to schedule the pause or it entered PIP mode,
-            // so just treat it as being paused now.
-            ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next.");
-            if (resuming == null) {
-                mRootWindowContainer.resumeFocusedTasksTopActivities();
-            }
-            return false;
-        }
-    }
-
-    @VisibleForTesting
-    void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
-        // Complete the pausing process of a pausing activity, so it doesn't make sense to
-        // operate on non-leaf tasks.
-        warnForNonLeafTask("completePauseLocked");
-
-        ActivityRecord prev = mPausingActivity;
-        ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
-
-        if (prev != null) {
-            prev.setWillCloseOrEnterPip(false);
-            final boolean wasStopping = prev.isState(STOPPING);
-            prev.setState(PAUSED, "completePausedLocked");
-            if (prev.finishing) {
-                // We will update the activity visibility later, no need to do in
-                // completeFinishing(). Updating visibility here might also making the next
-                // activities to be resumed, and could result in wrong app transition due to
-                // lack of previous activity information.
-                ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
-                prev = prev.completeFinishing(false /* updateVisibility */,
-                        "completePausedLocked");
-            } else if (prev.hasProcess()) {
-                ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
-                        + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
-                        prev.mVisibleRequested);
-                if (prev.deferRelaunchUntilPaused) {
-                    // Complete the deferred relaunch that was waiting for pause to complete.
-                    ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
-                    prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
-                } else if (wasStopping) {
-                    // We are also stopping, the stop request must have gone soon after the pause.
-                    // We can't clobber it, because the stop confirmation will not be handled.
-                    // We don't need to schedule another stop, we only need to let it happen.
-                    prev.setState(STOPPING, "completePausedLocked");
-                } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) {
-                    // Clear out any deferred client hide we might currently have.
-                    prev.setDeferHidingClient(false);
-                    // If we were visible then resumeTopActivities will release resources before
-                    // stopping.
-                    prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */,
-                            "completePauseLocked");
-                }
-            } else {
-                ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
-                prev = null;
-            }
-            // It is possible the activity was freezing the screen before it was paused.
-            // In that case go ahead and remove the freeze this activity has on the screen
-            // since it is no longer visible.
-            if (prev != null) {
-                prev.stopFreezingScreenLocked(true /*force*/);
-            }
-            mPausingActivity = null;
-        }
-
-        if (resumeNext) {
-            final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
-            if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
-                mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev, null);
-            } else {
-                checkReadyForSleep();
-                final ActivityRecord top =
-                        topRootTask != null ? topRootTask.topRunningActivity() : null;
-                if (top == null || (prev != null && top != prev)) {
-                    // If there are no more activities available to run, do resume anyway to start
-                    // something. Also if the top activity on the root task is not the just paused
-                    // activity, we need to go ahead and resume it to ensure we complete an
-                    // in-flight app switch.
-                    mRootWindowContainer.resumeFocusedTasksTopActivities();
-                }
-            }
-        }
-
-        if (prev != null) {
-            prev.resumeKeyDispatchingLocked();
-        }
-
-        mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
-
-        // Notify when the task stack has changed, but only if visibilities changed (not just
-        // focus). Also if there is an active root pinned task - we always want to notify it about
-        // task stack changes, because its positioning may depend on it.
-        if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause
-                || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) {
-            mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
-            mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
-        }
+        }, true /* traverseTopToBottom */);
+        return sleepInProgress[0] == 0;
     }
 
     boolean isTopRootTaskInDisplayArea() {
@@ -5941,10 +4684,10 @@
      *                 The activity is either starting or resuming.
      *                 Caller should ensure starting activity is visible.
      * @param preserveWindows Flag indicating whether windows should be preserved when updating
-     *                        configuration in {@link mEnsureActivitiesVisibleHelper}.
+     *                        configuration in {@link EnsureActivitiesVisibleHelper}.
      * @param configChanges Parts of the configuration that changed for this activity for evaluating
      *                      if the screen should be frozen as part of
-     *                      {@link mEnsureActivitiesVisibleHelper}.
+     *                      {@link EnsureActivitiesVisibleHelper}.
      *
      */
     void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
@@ -5960,21 +4703,22 @@
      *                 The activity is either starting or resuming.
      *                 Caller should ensure starting activity is visible.
      * @param notifyClients Flag indicating whether the visibility updates should be sent to the
-     *                      clients in {@link mEnsureActivitiesVisibleHelper}.
+     *                      clients in {@link EnsureActivitiesVisibleHelper}.
      * @param preserveWindows Flag indicating whether windows should be preserved when updating
-     *                        configuration in {@link mEnsureActivitiesVisibleHelper}.
+     *                        configuration in {@link EnsureActivitiesVisibleHelper}.
      * @param configChanges Parts of the configuration that changed for this activity for evaluating
      *                      if the screen should be frozen as part of
-     *                      {@link mEnsureActivitiesVisibleHelper}.
+     *                      {@link EnsureActivitiesVisibleHelper}.
      */
     // TODO: Should be re-worked based on the fact that each task as a root task in most cases.
     void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
             boolean preserveWindows, boolean notifyClients) {
         mTaskSupervisor.beginActivityVisibilityUpdate();
         try {
-            forAllLeafTasks(task -> task.mEnsureActivitiesVisibleHelper.process(
-                    starting, configChanges, preserveWindows, notifyClients),
-                    true /* traverseTopToBottom */);
+            forAllLeafTasks(task -> {
+                task.updateActivityVisibilities(starting, configChanges, preserveWindows,
+                        notifyClients);
+            }, true /* traverseTopToBottom */);
 
             // Notify WM shell that task visibilities may have changed
             forAllTasks(task -> task.dispatchTaskInfoChangedIfNeeded(/* force */ false),
@@ -6049,25 +4793,6 @@
         }
     }
 
-    /** @see ActivityRecord#cancelInitializing() */
-    void cancelInitializingActivities() {
-        // We don't want to clear starting window for activities that aren't behind fullscreen
-        // activities as we need to display their starting window until they are done initializing.
-        checkBehindFullscreenActivity(null /* toCheck */, ActivityRecord::cancelInitializing);
-    }
-
-    /**
-     * If an activity {@param toCheck} is given, this method returns {@code true} if the activity
-     * is occluded by any fullscreen activity. If there is no {@param toCheck} and the handling
-     * function {@param handleBehindFullscreenActivity} is given, this method will pass all occluded
-     * activities to the function.
-     */
-    boolean checkBehindFullscreenActivity(ActivityRecord toCheck,
-            Consumer<ActivityRecord> handleBehindFullscreenActivity) {
-        return mCheckBehindFullscreenActivityHelper.process(
-                toCheck, handleBehindFullscreenActivity);
-    }
-
     /**
      * Ensure that the top activity in the root task is resumed.
      *
@@ -6108,7 +4833,8 @@
                     if (!child.isTopActivityFocusable()) {
                         continue;
                     }
-                    if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) {
+                    if (child.getVisibility(null /* starting */)
+                            != TASK_FRAGMENT_VISIBILITY_VISIBLE) {
                         break;
                     }
 
@@ -6155,383 +4881,25 @@
             return false;
         }
 
-        // Find the next top-most activity to resume in this root task that is not finishing and is
-        // focusable. If it is not focusable, we will fall into the case below to resume the
-        // top activity in the next focusable task.
-        ActivityRecord next = topRunningActivity(true /* focusableOnly */);
-
-        final boolean hasRunningActivity = next != null;
-
-        // TODO: Maybe this entire condition can get removed?
-        if (hasRunningActivity && !isAttached()) {
-            return false;
-        }
-
         mRootWindowContainer.cancelInitializingActivities();
 
-        if (!hasRunningActivity) {
-            // There are no activities left in the root task, let's look somewhere else.
+        final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
+        if (topActivity == null) {
+            // There are no activities left in this task, let's look somewhere else.
             return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
         }
 
-        next.delayedResume = false;
-        final TaskDisplayArea taskDisplayArea = getDisplayArea();
-
-        // If the top activity is the resumed one, nothing to do.
-        if (mResumedActivity == next && next.isState(RESUMED)
-                && taskDisplayArea.allResumedActivitiesComplete()) {
-            // Make sure we have executed any pending transitions, since there
-            // should be nothing left to do at this point.
-            executeAppTransition(options);
-            // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
-            // we still want to check if the visibility of other windows have changed (e.g. bringing
-            // a fullscreen window forward to cover another freeform activity.)
-            if (taskDisplayArea.inMultiWindowMode()) {
-                taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                        false /* preserveWindows */, true /* notifyClients */);
-            }
-            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
-                    + "resumed %s", next);
-            return false;
-        }
-
-        if (!next.canResumeByCompat()) {
-            return false;
-        }
-
-        // If we are currently pausing an activity, then don't do anything until that is done.
-        final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
-        if (!allPausedComplete) {
-            ProtoLog.v(WM_DEBUG_STATES,
-                    "resumeTopActivityLocked: Skip resume: some activity pausing.");
-
-            return false;
-        }
-
-        // If we are sleeping, and there is no resumed activity, and the top activity is paused,
-        // well that is the state we want.
-        if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
-            // Make sure we have executed any pending transitions, since there
-            // should be nothing left to do at this point.
-            executeAppTransition(options);
-            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and"
-                    + " all paused");
-            return false;
-        }
-
-        // Make sure that the user who owns this activity is started.  If not,
-        // we will just leave it as is because someone should be bringing
-        // another user's activities to the top of the stack.
-        if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
-            Slog.w(TAG, "Skipping resume of top activity " + next
-                    + ": user " + next.mUserId + " is stopped");
-            return false;
-        }
-
-        // The activity may be waiting for stop, but that is no longer
-        // appropriate for it.
-        mTaskSupervisor.mStoppingActivities.remove(next);
-
-        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
-
-        mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);
-
-        ActivityRecord lastResumed = null;
-        final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
-        if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTask()) {
-            // So, why aren't we using prev here??? See the param comment on the method. prev
-            // doesn't represent the last resumed activity. However, the last focus stack does if
-            // it isn't null.
-            lastResumed = lastFocusedRootTask.getResumedActivity();
-        }
-
-        boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
-        if (mResumedActivity != null) {
-            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
-            pausing |= startPausingLocked(false /* uiSleeping */, next,
-                    "resumeTopActivityInnerLocked");
-        }
-        if (pausing) {
-            ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to"
-                    + " start pausing");
-            // At this point we want to put the upcoming activity's process
-            // at the top of the LRU list, since we know we will be needing it
-            // very soon and it would be a waste to let it get killed if it
-            // happens to be sitting towards the end.
-            if (next.attachedToProcess()) {
-                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
-                        true /* activityChange */, false /* updateOomAdj */,
-                        false /* addPendingTopUid */);
-            } else if (!next.isProcessRunning()) {
-                // Since the start-process is asynchronous, if we already know the process of next
-                // activity isn't running, we can start the process earlier to save the time to wait
-                // for the current activity to be paused.
-                final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
-                mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
-                        isTop ? "pre-top-activity" : "pre-activity");
-            }
-            if (lastResumed != null) {
-                lastResumed.setWillCloseOrEnterPip(true);
-            }
-            return true;
-        } else if (mResumedActivity == next && next.isState(RESUMED)
-                && taskDisplayArea.allResumedActivitiesComplete()) {
-            // It is possible for the activity to be resumed when we paused back stacks above if the
-            // next activity doesn't have to wait for pause to complete.
-            // So, nothing else to-do except:
-            // Make sure we have executed any pending transitions, since there
-            // should be nothing left to do at this point.
-            executeAppTransition(options);
-            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed "
-                    + "(dontWaitForPause) %s", next);
-            return true;
-        }
-
-        // If the most recent activity was noHistory but was only stopped rather
-        // than stopped+finished because the device went to sleep, we need to make
-        // sure to finish it as we're making a new activity topmost.
-        if (shouldSleepActivities()) {
-            mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
-        }
-
-        if (prev != null && prev != next && next.nowVisible) {
-
-            // The next activity is already visible, so hide the previous
-            // activity's windows right now so we can show the new one ASAP.
-            // We only do this if the previous is finishing, which should mean
-            // it is on top of the one being resumed so hiding it quickly
-            // is good.  Otherwise, we want to do the normal route of allowing
-            // the resumed activity to be shown so we can decide if the
-            // previous should actually be hidden depending on whether the
-            // new one is found to be full-screen or not.
-            if (prev.finishing) {
-                prev.setVisibility(false);
-                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
-                        "Not waiting for visible to hide: " + prev
-                                + ", nowVisible=" + next.nowVisible);
-            } else {
-                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
-                        "Previous already visible but still waiting to hide: " + prev
-                                + ", nowVisible=" + next.nowVisible);
+        final boolean[] resumed = new boolean[1];
+        final TaskFragment topFragment = topActivity.getTaskFragment();
+        resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
+        forAllLeafTaskFragments(f -> {
+            if (topFragment == f) {
+                return;
             }
 
-        }
-
-        // Launching this app's activity, make sure the app is no longer
-        // considered stopped.
-        try {
-            mTaskSupervisor.getActivityMetricsLogger()
-                    .notifyBeforePackageUnstopped(next.packageName);
-            mAtmService.getPackageManager().setPackageStoppedState(
-                    next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
-        } catch (RemoteException e1) {
-        } catch (IllegalArgumentException e) {
-            Slog.w(TAG, "Failed trying to unstop package "
-                    + next.packageName + ": " + e);
-        }
-
-        // We are starting up the next activity, so tell the window manager
-        // that the previous one will be hidden soon.  This way it can know
-        // to ignore it when computing the desired screen orientation.
-        boolean anim = true;
-        final DisplayContent dc = taskDisplayArea.mDisplayContent;
-        if (prev != null) {
-            if (prev.finishing) {
-                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
-                        "Prepare close transition: prev=" + prev);
-                if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
-                    anim = false;
-                    dc.prepareAppTransition(TRANSIT_NONE);
-                } else {
-                    dc.prepareAppTransition(TRANSIT_CLOSE);
-                }
-                prev.setVisibility(false);
-            } else {
-                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
-                        "Prepare open transition: prev=" + prev);
-                if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
-                    anim = false;
-                    dc.prepareAppTransition(TRANSIT_NONE);
-                } else {
-                    dc.prepareAppTransition(TRANSIT_OPEN,
-                            next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
-                }
-            }
-        } else {
-            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
-            if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
-                anim = false;
-                dc.prepareAppTransition(TRANSIT_NONE);
-            } else {
-                dc.prepareAppTransition(TRANSIT_OPEN);
-            }
-        }
-
-        if (anim) {
-            next.applyOptionsAnimation();
-        } else {
-            next.abortAndClearOptionsAnimation();
-        }
-
-        mTaskSupervisor.mNoAnimActivities.clear();
-
-        if (next.attachedToProcess()) {
-            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
-                    + " stopped=" + next.stopped
-                    + " visibleRequested=" + next.mVisibleRequested);
-
-            // If the previous activity is translucent, force a visibility update of
-            // the next activity, so that it's added to WM's opening app list, and
-            // transition animation can be set up properly.
-            // For example, pressing Home button with a translucent activity in focus.
-            // Launcher is already visible in this case. If we don't add it to opening
-            // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
-            // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
-            final boolean lastActivityTranslucent = lastFocusedRootTask != null
-                    && (lastFocusedRootTask.inMultiWindowMode()
-                    || (lastFocusedRootTask.mLastPausedActivity != null
-                    && !lastFocusedRootTask.mLastPausedActivity.occludesParent()));
-
-            // This activity is now becoming visible.
-            if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
-                next.setVisibility(true);
-            }
-
-            // schedule launch ticks to collect information about slow apps.
-            next.startLaunchTickingLocked();
-
-            ActivityRecord lastResumedActivity =
-                    lastFocusedRootTask == null ? null : lastFocusedRootTask.getResumedActivity();
-            final ActivityState lastState = next.getState();
-
-            mAtmService.updateCpuStats();
-
-            ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
-
-            next.setState(RESUMED, "resumeTopActivityInnerLocked");
-
-            // Have the window manager re-evaluate the orientation of
-            // the screen based on the new activity order.
-            boolean notUpdated = true;
-
-            // Activity should also be visible if set mLaunchTaskBehind to true (see
-            // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
-            if (shouldBeVisible(next)) {
-                // We have special rotation behavior when here is some active activity that
-                // requests specific orientation or Keyguard is locked. Make sure all activity
-                // visibilities are set correctly as well as the transition is updated if needed
-                // to get the correct rotation behavior. Otherwise the following call to update
-                // the orientation may cause incorrect configurations delivered to client as a
-                // result of invisible window resize.
-                // TODO: Remove this once visibilities are set correctly immediately when
-                // starting an activity.
-                notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
-                        true /* markFrozenIfConfigChanged */, false /* deferResume */);
-            }
-
-            if (notUpdated) {
-                // The configuration update wasn't able to keep the existing
-                // instance of the activity, and instead started a new one.
-                // We should be all done, but let's just make sure our activity
-                // is still at the top and schedule another run if something
-                // weird happened.
-                ActivityRecord nextNext = topRunningActivity();
-                ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
-                        + "%s, new next: %s", next, nextNext);
-                if (nextNext != next) {
-                    // Do over!
-                    mTaskSupervisor.scheduleResumeTopActivities();
-                }
-                if (!next.mVisibleRequested || next.stopped) {
-                    next.setVisibility(true);
-                }
-                next.completeResumeLocked();
-                return true;
-            }
-
-            try {
-                final ClientTransaction transaction =
-                        ClientTransaction.obtain(next.app.getThread(), next.appToken);
-                // Deliver all pending results.
-                ArrayList<ResultInfo> a = next.results;
-                if (a != null) {
-                    final int N = a.size();
-                    if (!next.finishing && N > 0) {
-                        if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
-                                "Delivering results to " + next + ": " + a);
-                        transaction.addCallback(ActivityResultItem.obtain(a));
-                    }
-                }
-
-                if (next.newIntents != null) {
-                    transaction.addCallback(
-                            NewIntentItem.obtain(next.newIntents, true /* resume */));
-                }
-
-                // Well the app will no longer be stopped.
-                // Clear app token stopped state in window manager if needed.
-                next.notifyAppResumed(next.stopped);
-
-                EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
-                        next.getTask().mTaskId, next.shortComponentName);
-
-                mAtmService.getAppWarningsLocked().onResumeActivity(next);
-                next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
-                next.abortAndClearOptionsAnimation();
-                transaction.setLifecycleStateRequest(
-                        ResumeActivityItem.obtain(next.app.getReportedProcState(),
-                                dc.isNextTransitionForward()));
-                mAtmService.getLifecycleManager().scheduleTransaction(transaction);
-
-                ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Resumed %s", next);
-            } catch (Exception e) {
-                // Whoops, need to restart this activity!
-                ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
-                        + "%s", lastState, next);
-                next.setState(lastState, "resumeTopActivityInnerLocked");
-
-                // lastResumedActivity being non-null implies there is a lastStack present.
-                if (lastResumedActivity != null) {
-                    lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
-                }
-
-                Slog.i(TAG, "Restarting because process died: " + next);
-                if (!next.hasBeenLaunched) {
-                    next.hasBeenLaunched = true;
-                } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
-                        && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
-                    next.showStartingWindow(false /* taskSwitch */);
-                }
-                mTaskSupervisor.startSpecificActivity(next, true, false);
-                return true;
-            }
-
-            // From this point on, if something goes wrong there is no way
-            // to recover the activity.
-            try {
-                next.completeResumeLocked();
-            } catch (Exception e) {
-                // If any exception gets thrown, toss away this
-                // activity and try the next one.
-                Slog.w(TAG, "Exception thrown during resume of " + next, e);
-                next.finishIfPossible("resume-exception", true /* oomAdj */);
-                return true;
-            }
-        } else {
-            // Whoops, need to restart this activity!
-            if (!next.hasBeenLaunched) {
-                next.hasBeenLaunched = true;
-            } else {
-                if (SHOW_APP_STARTING_PREVIEW) {
-                    next.showStartingWindow(false /* taskSwich */);
-                }
-                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
-            }
-            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next);
-            mTaskSupervisor.startSpecificActivity(next, true, true);
-        }
-
-        return true;
+            resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
+        }, true);
+        return resumed[0];
     }
 
     /**
@@ -7212,13 +5580,6 @@
         return true;
     }
 
-    /**
-     * Ensures all visible activities at or below the input activity have the right configuration.
-     */
-    void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
-        mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
-    }
-
     // TODO: Can only be called from special methods in ActivityTaskSupervisor.
     // Need to consolidate those calls points into this resize method so anyone can call directly.
     void resize(Rect displayedBounds, boolean preserveWindows, boolean deferResume) {
@@ -7272,114 +5633,35 @@
         }
     }
 
-    /**
-     * Reset local parameters because an app's activity died.
-     * @param app The app of the activity that died.
-     * @return {@code true} if the process of the pausing activity is died.
-     */
-    boolean handleAppDied(WindowProcessController app) {
-        warnForNonLeafTask("handleAppDied");
-        boolean isPausingDied = false;
-        if (mPausingActivity != null && mPausingActivity.app == app) {
-            ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s",
-                    mPausingActivity);
-            mPausingActivity = null;
-            isPausingDied = true;
-        }
-        if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
-            if (mLastPausedActivity.isNoHistory()) {
-                mTaskSupervisor.mNoHistoryActivities.remove(mLastPausedActivity);
-            }
-            mLastPausedActivity = null;
-        }
-        return isPausingDied;
-    }
-
     boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
             String dumpPackage, final boolean needSep) {
-        Runnable headerPrinter = () -> {
-            if (needSep) {
-                pw.println();
-            }
-            pw.println("  RootTask #" + getRootTaskId()
-                    + ": type=" + activityTypeToString(getActivityType())
-                    + " mode=" + windowingModeToString(getWindowingMode()));
-            pw.println("  isSleeping=" + shouldSleepActivities());
-            pw.println("  mBounds=" + getRequestedOverrideBounds());
-            pw.println("  mCreatedByOrganizer=" + mCreatedByOrganizer);
-        };
-
-        boolean printed = false;
-
-        if (dumpPackage == null) {
-            // If we are not filtering by package, we want to print absolutely everything,
-            // so always print the header even if there are no tasks/activities inside.
-            headerPrinter.run();
-            headerPrinter = null;
-            printed = true;
-        }
-
-        printed |= printThisActivity(pw, getPausingActivity(), dumpPackage, false,
-                "    mPausingActivity: ", null);
-        printed |= printThisActivity(pw, getResumedActivity(), dumpPackage, false,
-                "    mResumedActivity: ", null);
-        if (dumpAll) {
-            printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
-                    "    mLastPausedActivity: ", null);
-        }
-
-        printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter);
-
-        return printed;
+        return dump("  ", fd, pw, dumpAll, dumpClient, dumpPackage, needSep, null /* header */);
     }
 
-    private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
-            boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) {
-        if (!hasChild()) {
-            return false;
+    @Override
+    void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
+        pw.print(prefix); pw.print("* "); pw.println(this);
+        pw.println(prefix + "  mBounds=" + getRequestedOverrideBounds());
+        pw.println(prefix + "  mCreatedByOrganizer=" + mCreatedByOrganizer);
+        if (mLastNonFullscreenBounds != null) {
+            pw.print(prefix); pw.print("  mLastNonFullscreenBounds=");
+            pw.println(mLastNonFullscreenBounds);
         }
-        final AtomicBoolean printedHeader = new AtomicBoolean(false);
-        final AtomicBoolean printed = new AtomicBoolean(false);
-        forAllLeafTasks((task) -> {
-            final String prefix = "    ";
-            Runnable headerPrinter = () -> {
-                printed.set(true);
-                if (!printedHeader.get()) {
-                    if (needSep) {
-                        pw.println("");
-                    }
-                    if (header != null) {
-                        header.run();
-                    }
-                    printedHeader.set(true);
-                }
-                pw.print(prefix); pw.print("* "); pw.println(task);
-                pw.print(prefix); pw.print("  mBounds=");
-                pw.println(task.getRequestedOverrideBounds());
-                pw.print(prefix); pw.print("  mMinWidth="); pw.print(task.mMinWidth);
-                pw.print(" mMinHeight="); pw.println(task.mMinHeight);
-                if (mLastNonFullscreenBounds != null) {
-                    pw.print(prefix);
-                    pw.print("  mLastNonFullscreenBounds=");
-                    pw.println(task.mLastNonFullscreenBounds);
-                }
-                task.dump(pw, prefix + "  ");
-            };
-            if (dumpPackage == null) {
-                // If we are not filtering by package, we want to print absolutely everything,
-                // so always print the header even if there are no activities inside.
-                headerPrinter.run();
-                headerPrinter = null;
+        if (dumpAll) {
+            printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
+                    prefix + "  mLastPausedActivity: ", null);
+        }
+        if (isLeafTask()) {
+            pw.println(prefix + "  isSleeping=" + shouldSleepActivities());
+            printThisActivity(pw, getTopPausingActivity(), dumpPackage, false,
+                    prefix + "  topPausingActivity=", null);
+            printThisActivity(pw, getTopResumedActivity(), dumpPackage, false,
+                    prefix + "  topResumedActivity=", null);
+            if (mMinWidth != INVALID_MIN_SIZE || mMinHeight != INVALID_MIN_SIZE) {
+                pw.print(prefix); pw.print("  mMinWidth="); pw.print(mMinWidth);
+                pw.print(" mMinHeight="); pw.println(mMinHeight);
             }
-            final ArrayList<ActivityRecord> activities = new ArrayList<>();
-            // Add activities by traversing the hierarchy from bottom to top, since activities
-            // are dumped in reverse order in {@link ActivityTaskSupervisor#dumpHistoryList()}.
-            task.forAllActivities((Consumer<ActivityRecord>) activities::add,
-                    false /* traverseTopToBottom */);
-            dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
-                    dumpPackage, false, headerPrinter, task);
-        }, true /* traverseTopToBottom */);
-        return printed.get();
+        }
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -7779,6 +6061,7 @@
         return mAnimatingActivityRegistry;
     }
 
+    @Override
     void executeAppTransition(ActivityOptions options) {
         mDisplayContent.executeAppTransition();
         ActivityOptions.abort(options);
@@ -7801,10 +6084,6 @@
         return display != null ? display.isSleeping() : mAtmService.isSleepingLocked();
     }
 
-    boolean shouldSleepOrShutDownActivities() {
-        return shouldSleepActivities() || mAtmService.mShuttingDown;
-    }
-
     private Rect getRawBounds() {
         return super.getBounds();
     }
@@ -7823,14 +6102,12 @@
         }
 
         final long token = proto.start(fieldId);
-        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
 
         proto.write(TaskProto.ID, mTaskId);
-        proto.write(DISPLAY_ID, getDisplayId());
         proto.write(ROOT_TASK_ID, getRootTaskId());
 
-        if (mResumedActivity != null) {
-            mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+        if (getTopResumedActivity() != null) {
+            getTopResumedActivity().writeIdentifierToProto(proto, RESUMED_ACTIVITY);
         }
         if (realActivity != null) {
             proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
@@ -7838,11 +6115,7 @@
         if (origActivity != null) {
             proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
         }
-        proto.write(ACTIVITY_TYPE, getActivityType());
         proto.write(RESIZE_MODE, mResizeMode);
-        proto.write(MIN_WIDTH, mMinWidth);
-        proto.write(MIN_HEIGHT, mMinHeight);
-
         proto.write(FILLS_PARENT, matchParentBounds());
         getRawBounds().dumpDebug(proto, BOUNDS);
 
@@ -7859,6 +6132,8 @@
         proto.write(AFFINITY, affinity);
         proto.write(HAS_CHILD_PIP_ACTIVITY, mChildPipActivity != null);
 
+        super.dumpDebug(proto, TASK_FRAGMENT, logLevel);
+
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index d450dbf..99b7c75 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -34,11 +34,10 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+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.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+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;
 
@@ -469,7 +468,7 @@
         // Update the top resumed activity because the preferred top focusable task may be changed.
         mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded();
 
-        final ActivityRecord r = child.getResumedActivity();
+        final ActivityRecord r = child.getTopResumedActivity();
         if (r != null && r == mRootWindowContainer.getTopResumedActivity()) {
             mAtmService.setResumedActivityUncheckLocked(r, "positionChildAt");
         }
@@ -1231,7 +1230,7 @@
                                 + adjacentFlagRootTask);
             }
 
-            if (adjacentFlagRootTask.mAdjacentTask == null) {
+            if (adjacentFlagRootTask.getAdjacentTaskFragment() == null) {
                 throw new UnsupportedOperationException(
                         "Can't set non-adjacent root as launch adjacent flag root tr="
                                 + adjacentFlagRootTask);
@@ -1269,8 +1268,8 @@
             // If the adjacent launch is coming from the same root, launch to adjacent root instead.
             if (sourceTask != null
                     && sourceTask.getRootTask().mTaskId == mLaunchAdjacentFlagRootTask.mTaskId
-                    && mLaunchAdjacentFlagRootTask.mAdjacentTask != null) {
-                return mLaunchAdjacentFlagRootTask.mAdjacentTask;
+                    && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null) {
+                return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask();
             } else {
                 return mLaunchAdjacentFlagRootTask;
             }
@@ -1280,8 +1279,10 @@
             if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
                 final Task launchRootTask = mLaunchRootTasks.get(i).task;
                 // Return the focusable root task for improving the UX with staged split screen.
-                final Task adjacentRootTask = launchRootTask != null
-                        ? launchRootTask.mAdjacentTask : null;
+                final TaskFragment adjacentTaskFragment = launchRootTask != null
+                        ? launchRootTask.getAdjacentTaskFragment() : null;
+                final Task adjacentRootTask =
+                        adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null;
                 if (adjacentRootTask != null && adjacentRootTask.isFocusedRootTaskOnDisplay()) {
                     return adjacentRootTask;
                 } else {
@@ -1373,11 +1374,11 @@
         }
         // TODO(b/111541062): Move this into Task#getResumedActivity()
         // Check if the focused root task has the resumed activity
-        ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
+        ActivityRecord resumedActivity = focusedRootTask.getTopResumedActivity();
         if (resumedActivity == null || resumedActivity.app == null) {
             // If there is no registered resumed activity in the root task or it is not running -
             // try to use previously resumed one.
-            resumedActivity = focusedRootTask.getPausingActivity();
+            resumedActivity = focusedRootTask.getTopPausingActivity();
             if (resumedActivity == null || resumedActivity.app == null) {
                 // If previously resumed activity doesn't work either - find the topmost running
                 // activity that can be focused.
@@ -1425,7 +1426,7 @@
                 continue;
             }
 
-            final ActivityRecord r = mChildren.get(i).asTask().getResumedActivity();
+            final ActivityRecord r = mChildren.get(i).asTask().getTopResumedActivity();
             if (r != null && !r.isState(RESUMED)) {
                 return false;
             }
@@ -1451,18 +1452,30 @@
      */
     boolean pauseBackTasks(ActivityRecord resuming) {
         final int[] someActivityPaused = {0};
-        forAllLeafTasks((task) -> {
-            final ActivityRecord resumedActivity = task.getResumedActivity();
-            if (resumedActivity != null
-                    && (task.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE
-                    || !task.isTopActivityFocusable())) {
-                ProtoLog.d(WM_DEBUG_STATES, "pauseBackTasks: task=%s "
-                        + "mResumedActivity=%s", task, resumedActivity);
-                if (task.startPausingLocked(false /* uiSleeping*/,
-                        resuming, "pauseBackTasks")) {
-                    someActivityPaused[0]++;
+        forAllLeafTasks(leafTask -> {
+            // Check if the direct child resumed activity in the leaf task needed to be paused if
+            // the leaf task is not a leaf task fragment.
+            if (!leafTask.isLeafTaskFragment()) {
+                final ActivityRecord top = topRunningActivity();
+                final ActivityRecord resumedActivity = leafTask.getResumedActivity();
+                if (resumedActivity != null && top.getTaskFragment() != leafTask) {
+                    // Pausing the resumed activity because it is occluded by other task fragment.
+                    if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
+                        someActivityPaused[0]++;
+                    }
                 }
             }
+
+            leafTask.forAllLeafTaskFragments((taskFrag) -> {
+                final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
+                if (resumedActivity != null
+                        && (taskFrag.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE
+                        || !taskFrag.isTopActivityFocusable())) {
+                    if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
+                        someActivityPaused[0]++;
+                    }
+                }
+            }, true /* traverseTopToBottom */);
         }, true /* traverseTopToBottom */);
         return someActivityPaused[0] > 0;
     }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
new file mode 100644
index 0000000..d86682b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -0,0 +1,2095 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.os.UserHandle.USER_NULL;
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
+import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.IdentifierProto.TITLE;
+import static com.android.server.wm.IdentifierProto.USER_ID;
+import static com.android.server.wm.TaskFragmentProto.ACTIVITY_TYPE;
+import static com.android.server.wm.TaskFragmentProto.DISPLAY_ID;
+import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
+import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
+import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.app.ResultInfo;
+import android.app.WindowConfiguration;
+import android.app.servertransaction.ActivityResultItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.NewIntentItem;
+import android.app.servertransaction.PauseActivityItem;
+import android.app.servertransaction.ResumeActivityItem;
+import android.content.ComponentName;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
+import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A basic container that can be used to contain activities or other {@link TaskFragment}, which
+ * also able to manage the activity lifecycle and updates the visibilities of the activities in it.
+ */
+class TaskFragment extends WindowContainer<WindowContainer> {
+    @IntDef(prefix = {"TASK_FRAGMENT_VISIBILITY"}, value = {
+            TASK_FRAGMENT_VISIBILITY_VISIBLE,
+            TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+            TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+    })
+    @interface TaskFragmentVisibility {}
+
+    /**
+     * TaskFragment is visible. No other TaskFragment(s) on top that fully or partially occlude it.
+     */
+    static final int TASK_FRAGMENT_VISIBILITY_VISIBLE = 0;
+
+    /** TaskFragment is partially occluded by other translucent TaskFragment(s) on top of it. */
+    static final int TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
+
+    /** TaskFragment is completely invisible. */
+    static final int TASK_FRAGMENT_VISIBILITY_INVISIBLE = 2;
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskFragment" : TAG_ATM;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+    private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+
+    /** Set to false to disable the preview that is shown while a new activity is being started. */
+    static final boolean SHOW_APP_STARTING_PREVIEW = true;
+
+    /**
+     * Indicate that the minimal width/height should use the default value.
+     *
+     * @see #mMinWidth
+     * @see #mMinHeight
+     */
+    static final int INVALID_MIN_SIZE = -1;
+
+    final ActivityTaskManagerService mAtmService;
+    final ActivityTaskSupervisor mTaskSupervisor;
+    final RootWindowContainer mRootWindowContainer;
+    private final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
+
+    // TODO(b/189384393): this is not set in TaskFragment so far. It should be passed from the
+    // parent task when adding to the hierarchy
+    /**
+     * Minimal width of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
+     * should use the default minimal width.
+     */
+    int mMinWidth;
+    // TODO(b/189384393): this is not set in TaskFragment so far. It should be passed from the
+    // parent task when adding to the hierarchy
+    /**
+     * Minimal height of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
+     * should use the default minimal height.
+     */
+    int mMinHeight;
+
+    // The TaskFragment that adjacent to this one.
+    private TaskFragment mAdjacentTaskFragment;
+
+    /**
+     * When we are in the process of pausing an activity, before starting the
+     * next one, this variable holds the activity that is currently being paused.
+     *
+     * Only set at leaf task fragments.
+     */
+    @Nullable
+    private ActivityRecord mPausingActivity = null;
+
+    /**
+     * This is the last activity that we put into the paused state.  This is
+     * used to determine if we need to do an activity transition while sleeping,
+     * when we normally hold the top activity paused.
+     */
+    // TODO(b/189384393): check whether this should work on root task or leaf.
+    ActivityRecord mLastPausedActivity = null;
+
+    /**
+     * Current activity that is resumed, or null if there is none.
+     * Only set at leaf task fragments.
+     */
+    @Nullable
+    private ActivityRecord mResumedActivity = null;
+
+    /**
+     * This TaskFragment was created by an organizer which has the following implementations.
+     * <ul>
+     *     <li>The TaskFragment won't be removed when it is empty. Removal has to be an explicit
+     *     request from the organizer.</li>
+     *     <li>If this fragment is a Task object then unlike other non-root tasks, it's direct
+     *     children are visible to the organizer for ordering purposes.</li>
+     *     <li>A TaskFragment can be created by {@link android.window.TaskFragmentOrganizer}, and
+     *     a Task can be created by {@link android.window.TaskOrganizer}.</li>
+     * </ul>
+     */
+    @VisibleForTesting
+    boolean mCreatedByOrganizer;
+
+    /** Organizer that organizing this TaskFragment. */
+    // TODO(b/190433129) set the value when creating TaskFragment from WCT.
+    @Nullable
+    private ITaskFragmentOrganizer mTaskFragmentOrganizer;
+
+    /** Client assigned unique token for this TaskFragment if this is created by an organizer. */
+    // TODO(b/190433129) set the value when creating TaskFragment from WCT.
+    @Nullable
+    private IBinder mFragmentToken;
+
+    /**
+     * The component name of the root activity that initiated this TaskFragment, which will be used
+     * to configure the relationships for TaskFragments.
+     */
+    // TODO(b/190433129) set the value when creating TaskFragment from WCT.
+    @Nullable
+    private ComponentName mInitialComponentName;
+
+    private final Rect mTmpInsets = new Rect();
+    private final Rect mTmpBounds = new Rect();
+    private final Rect mTmpFullBounds = new Rect();
+    private final Rect mTmpStableBounds = new Rect();
+    private final Rect mTmpNonDecorBounds = new Rect();
+
+    private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
+            new EnsureActivitiesVisibleHelper(this);
+    private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
+            new EnsureVisibleActivitiesConfigHelper();
+    private class EnsureVisibleActivitiesConfigHelper {
+        private boolean mUpdateConfig;
+        private boolean mPreserveWindow;
+        private boolean mBehindFullscreen;
+
+        void reset(boolean preserveWindow) {
+            mPreserveWindow = preserveWindow;
+            mUpdateConfig = false;
+            mBehindFullscreen = false;
+        }
+
+        void process(ActivityRecord start, boolean preserveWindow) {
+            if (start == null || !start.mVisibleRequested) {
+                return;
+            }
+            reset(preserveWindow);
+
+            final PooledFunction f = PooledLambda.obtainFunction(
+                    EnsureVisibleActivitiesConfigHelper::processActivity, this,
+                    PooledLambda.__(ActivityRecord.class));
+            forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/);
+            f.recycle();
+
+            if (mUpdateConfig) {
+                // TODO(b/189384393): rename to resumeFocusedTaskFragmentsTopActivities
+                // Ensure the resumed state of the focus activity if we updated the configuration of
+                // any activity.
+                mRootWindowContainer.resumeFocusedTasksTopActivities();
+            }
+        }
+
+        boolean processActivity(ActivityRecord r) {
+            mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
+            mBehindFullscreen |= r.occludesParent();
+            return mBehindFullscreen;
+        }
+    }
+
+    TaskFragment(ActivityTaskManagerService atmService, boolean createdByOrganizer) {
+        super(atmService.mWindowManager);
+
+        mAtmService = atmService;
+        mTaskSupervisor = atmService.mTaskSupervisor;
+        mRootWindowContainer = mAtmService.mRootWindowContainer;
+        mCreatedByOrganizer = createdByOrganizer;
+        mTaskFragmentOrganizerController =
+                mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
+    }
+
+    void setAdjacentTaskFragment(TaskFragment taskFragment) {
+        mAdjacentTaskFragment = taskFragment;
+        taskFragment.mAdjacentTaskFragment = this;
+    }
+
+    TaskFragment getAdjacentTaskFragment() {
+        return mAdjacentTaskFragment;
+    }
+
+    /** @return the currently resumed activity. */
+    ActivityRecord getResumedActivity() {
+        return mResumedActivity;
+    }
+
+    void setResumedActivity(ActivityRecord r, String reason) {
+        warnForNonLeafTaskFragment("setResumedActivity");
+        if (mResumedActivity == r) {
+            return;
+        }
+
+        if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+            Slog.d(TAG, "setResumedActivity taskFrag:" + this + " + from: "
+                    + mResumedActivity + " to:" + r + " reason:" + reason);
+        }
+        mResumedActivity = r;
+        mTaskSupervisor.updateTopResumedActivityIfNeeded();
+    }
+
+    @VisibleForTesting
+    void setPausingActivity(ActivityRecord pausing) {
+        mPausingActivity = pausing;
+    }
+
+    ActivityRecord getPausingActivity() {
+        return mPausingActivity;
+    }
+
+    int getDisplayId() {
+        final DisplayContent dc = getDisplayContent();
+        return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
+    }
+
+    @Nullable
+    Task getTask() {
+        if (asTask() != null) {
+            return asTask();
+        }
+
+        TaskFragment parent = getParent() != null ? getParent().asTaskFragment() : null;
+        return parent != null ? parent.getTask() : null;
+    }
+
+    @Override
+    @Nullable
+    TaskDisplayArea getDisplayArea() {
+        return (TaskDisplayArea) super.getDisplayArea();
+    }
+
+    @Override
+    public boolean isAttached() {
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+        return taskDisplayArea != null && !taskDisplayArea.isRemoved();
+    }
+
+    /**
+     * Returns the root {@link TaskFragment}, which is usually also a {@link Task}.
+     */
+    @NonNull
+    TaskFragment getRootTaskFragment() {
+        final WindowContainer parent = getParent();
+        if (parent == null) return this;
+
+        final TaskFragment parentTaskFragment = parent.asTaskFragment();
+        return parentTaskFragment == null ? this : parentTaskFragment.getRootTaskFragment();
+    }
+
+    @Override
+    TaskFragment asTaskFragment() {
+        return this;
+    }
+
+
+    /**
+     * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}.
+     */
+    private void warnForNonLeafTaskFragment(String func) {
+        if (!isLeafTaskFragment()) {
+            Slog.w(TAG, func + " on non-leaf task fragment " + this);
+        }
+    }
+
+    boolean hasDirectChildActivities() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            if (mChildren.get(i).asActivityRecord() != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void cleanUpActivityReferences(ActivityRecord r) {
+        if (mPausingActivity != null && mPausingActivity == r) {
+            mPausingActivity = null;
+        }
+
+        if (mResumedActivity != null && mResumedActivity == r) {
+            setResumedActivity(null, "cleanUpActivityReferences");
+        }
+
+        // TODO(b/189384393): why clean up the references in parents while the references are
+        //  kept in the leaf?
+        final WindowContainer parent = getParent();
+        if (parent != null && parent.asTaskFragment() != null) {
+            parent.asTaskFragment().cleanUpActivityReferences(r);
+            return;
+        }
+        r.removeTimeouts();
+    }
+
+    /**
+     * Returns whether this TaskFragment is currently forced to be hidden for any reason.
+     */
+    protected boolean isForceHidden() {
+        return false;
+    }
+
+    boolean isLeafTaskFragment() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            if (mChildren.get(i).asTaskFragment() != null) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * This should be called when an child activity changes state. This should only
+     * be called from
+     * {@link ActivityRecord#setState(ActivityRecord.State, String)} .
+     * @param record The {@link ActivityRecord} whose state has changed.
+     * @param state The new state.
+     * @param reason The reason for the change.
+     */
+    void onActivityStateChanged(ActivityRecord record, ActivityRecord.State state,
+            String reason) {
+        warnForNonLeafTaskFragment("onActivityStateChanged");
+        if (record == mResumedActivity && state != RESUMED) {
+            setResumedActivity(null, reason + " - onActivityStateChanged");
+        }
+
+        if (state == RESUMED) {
+            if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+                Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason);
+            }
+            setResumedActivity(record, reason + " - onActivityStateChanged");
+            if (record == mRootWindowContainer.getTopResumedActivity()) {
+                mAtmService.setResumedActivityUncheckLocked(record, reason);
+            }
+            mTaskSupervisor.mRecentTasks.add(record.getTask());
+        }
+    }
+
+    /**
+     * Resets local parameters because an app's activity died.
+     * @param app The app of the activity that died.
+     * @return {@code true} if the process of the pausing activity is died.
+     */
+    boolean handleAppDied(WindowProcessController app) {
+        warnForNonLeafTaskFragment("handleAppDied");
+        boolean isPausingDied = false;
+        if (mPausingActivity != null && mPausingActivity.app == app) {
+            ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s",
+                    mPausingActivity);
+            mPausingActivity = null;
+            isPausingDied = true;
+        }
+        if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
+            if (mLastPausedActivity.isNoHistory()) {
+                mTaskSupervisor.mNoHistoryActivities.remove(mLastPausedActivity);
+            }
+            mLastPausedActivity = null;
+        }
+        return isPausingDied;
+    }
+
+    void awakeFromSleeping() {
+        if (mPausingActivity != null) {
+            Slog.d(TAG, "awakeFromSleeping: previously pausing activity didn't pause");
+            mPausingActivity.activityPaused(true);
+        }
+    }
+
+    /**
+     * Tries to put the activities in the task fragment to sleep.
+     *
+     * If the task fragment is not in a state where its activities can be put to sleep, this
+     * function will start any necessary actions to move the task fragment into such a state.
+     * It is expected that this function get called again when those actions complete.
+     *
+     * @param shuttingDown {@code true} when the called because the device is shutting down.
+     * @return true if the root task finished going to sleep, false if the root task only started
+     * the process of going to sleep (checkReadyForSleep will be called when that process finishes).
+     */
+    boolean sleepIfPossible(boolean shuttingDown) {
+        boolean shouldSleep = true;
+        if (mResumedActivity != null) {
+            // Still have something resumed; can't sleep until it is paused.
+            ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity);
+            startPausing(false /* userLeaving */, true /* uiSleeping */, null /* resuming */,
+                    "sleep");
+            shouldSleep = false;
+        } else if (mPausingActivity != null) {
+            // Still waiting for something to pause; can't sleep yet.
+            ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity);
+            shouldSleep = false;
+        }
+
+        if (!shuttingDown) {
+            if (containsStoppingActivity()) {
+                // Still need to tell some activities to stop; can't sleep yet.
+                ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities",
+                        mTaskSupervisor.mStoppingActivities.size());
+
+                mTaskSupervisor.scheduleIdle();
+                shouldSleep = false;
+            }
+        }
+
+        if (shouldSleep) {
+            updateActivityVisibilities(null /* starting */, 0 /* configChanges */,
+                    !PRESERVE_WINDOWS, true /* notifyClients */);
+        }
+
+        return shouldSleep;
+    }
+
+    private boolean containsStoppingActivity() {
+        for (int i = mTaskSupervisor.mStoppingActivities.size() - 1; i >= 0; --i) {
+            ActivityRecord r = mTaskSupervisor.mStoppingActivities.get(i);
+            if (r.getTaskFragment() == this) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the TaskFragment is translucent and can have other contents visible behind
+     * it if needed. A TaskFragment is considered translucent if it don't contain a visible or
+     * starting (about to be visible) activity that is fullscreen (opaque).
+     * @param starting The currently starting activity or null if there is none.
+     */
+    @VisibleForTesting
+    boolean isTranslucent(ActivityRecord starting) {
+        if (!isAttached() || isForceHidden()) {
+            return true;
+        }
+        final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
+                PooledLambda.__(ActivityRecord.class), starting);
+        final ActivityRecord opaque = getActivity(p);
+        p.recycle();
+        return opaque == null;
+    }
+
+    private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
+        if (r.finishing) {
+            // We don't factor in finishing activities when determining translucency since
+            // they will be gone soon.
+            return false;
+        }
+
+        if (!r.visibleIgnoringKeyguard && r != starting) {
+            // Also ignore invisible activities that are not the currently starting
+            // activity (about to be visible).
+            return false;
+        }
+
+        if (r.occludesParent()) {
+            // Root task isn't translucent if it has at least one fullscreen activity
+            // that is visible.
+            return true;
+        }
+        return false;
+    }
+
+    ActivityRecord topRunningActivity() {
+        return topRunningActivity(false /* focusableOnly */);
+    }
+
+    ActivityRecord topRunningActivity(boolean focusableOnly) {
+        // Split into 2 to avoid object creation due to variable capture.
+        if (focusableOnly) {
+            return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
+        } else {
+            return getActivity(ActivityRecord::canBeTopRunning);
+        }
+    }
+
+    boolean isTopActivityFocusable() {
+        final ActivityRecord r = topRunningActivity();
+        return r != null ? r.isFocusable()
+                : (isFocusable() && getWindowConfiguration().canReceiveKeys());
+    }
+
+    /**
+     * Returns the visibility state of this TaskFragment.
+     *
+     * @param starting The currently starting activity or null if there is none.
+     */
+    @TaskFragmentVisibility
+    int getVisibility(ActivityRecord starting) {
+        if (!isAttached() || isForceHidden()) {
+            return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+        }
+
+        if (isTopActivityLaunchedBehind()) {
+            return TASK_FRAGMENT_VISIBILITY_VISIBLE;
+        }
+
+        boolean gotRootSplitScreenFragment = false;
+        boolean gotOpaqueSplitScreenPrimary = false;
+        boolean gotOpaqueSplitScreenSecondary = false;
+        boolean gotTranslucentFullscreen = false;
+        boolean gotTranslucentSplitScreenPrimary = false;
+        boolean gotTranslucentSplitScreenSecondary = false;
+        boolean shouldBeVisible = true;
+
+        // This TaskFragment is only considered visible if all its parent TaskFragments are
+        // considered visible, so check the visibility of all ancestor TaskFragment first.
+        final WindowContainer parent = getParent();
+        if (parent.asTaskFragment() != null) {
+            final int parentVisibility = parent.asTaskFragment().getVisibility(starting);
+            if (parentVisibility == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
+                // Can't be visible if parent isn't visible
+                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+            } else if (parentVisibility == TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
+                // Parent is behind a translucent container so the highest visibility this container
+                // can get is that.
+                gotTranslucentFullscreen = true;
+            }
+        }
+
+        final List<TaskFragment> adjacentTaskFragments = new ArrayList<>();
+        final int windowingMode = getWindowingMode();
+        final boolean isAssistantType = isActivityTypeAssistant();
+        for (int i = parent.getChildCount() - 1; i >= 0; --i) {
+            final WindowContainer other = parent.getChildAt(i);
+            if (other == null) continue;
+
+            final boolean hasRunningActivities = hasRunningActivity(other);
+            if (other == this) {
+                // Should be visible if there is no other fragment occluding it, unless it doesn't
+                // have any running activities, not starting one and not home stack.
+                shouldBeVisible = hasRunningActivities
+                        || (starting != null && starting.isDescendantOf(this))
+                        || isActivityTypeHome();
+                break;
+            }
+
+            if (!hasRunningActivities) {
+                continue;
+            }
+
+            final int otherWindowingMode = other.getWindowingMode();
+            if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+                if (isTranslucent(other, starting)) {
+                    // Can be visible behind a translucent fullscreen TaskFragment.
+                    gotTranslucentFullscreen = true;
+                    continue;
+                }
+                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+            } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW
+                    && other.matchParentBounds()) {
+                if (isTranslucent(other, starting)) {
+                    // Can be visible behind a translucent TaskFragment.
+                    gotTranslucentFullscreen = true;
+                    continue;
+                }
+                // Multi-window TaskFragment that matches parent bounds would occlude other children
+                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+            } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                    && !gotOpaqueSplitScreenPrimary) {
+                gotRootSplitScreenFragment = true;
+                gotTranslucentSplitScreenPrimary = isTranslucent(other, starting);
+                gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary;
+                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                        && gotOpaqueSplitScreenPrimary) {
+                    // Can't be visible behind another opaque TaskFragment in split-screen-primary.
+                    return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+                }
+            } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                    && !gotOpaqueSplitScreenSecondary) {
+                gotRootSplitScreenFragment = true;
+                gotTranslucentSplitScreenSecondary = isTranslucent(other, starting);
+                gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary;
+                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                        && gotOpaqueSplitScreenSecondary) {
+                    // Can't be visible behind another opaque TaskFragment in split-screen-secondary
+                    return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+                }
+            }
+            if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
+                // Can not be visible if we are in split-screen windowing mode and both halves of
+                // the screen are opaque.
+                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+            }
+            if (isAssistantType && gotRootSplitScreenFragment) {
+                // Assistant TaskFragment can't be visible behind split-screen. In addition to
+                // this not making sense, it also works around an issue here we boost the z-order
+                // of the assistant window surfaces in window manager whenever it is visible.
+                return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+            }
+
+            final TaskFragment otherTaskFrag = other.asTaskFragment();
+            if (otherTaskFrag != null && otherTaskFrag.mAdjacentTaskFragment != null) {
+                if (adjacentTaskFragments.contains(otherTaskFrag.mAdjacentTaskFragment)) {
+                    if (otherTaskFrag.isTranslucent(starting)
+                            || otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) {
+                        // Can be visible behind a translucent adjacent TaskFragments.
+                        gotTranslucentFullscreen = true;
+                        continue;
+                    }
+                    // Can not be visible behind adjacent TaskFragments.
+                    return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+                } else {
+                    adjacentTaskFragments.add(otherTaskFrag);
+                }
+            }
+
+        }
+
+        if (!shouldBeVisible) {
+            return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+        }
+
+        // Handle cases when there can be a translucent split-screen TaskFragment on top.
+        switch (windowingMode) {
+            case WINDOWING_MODE_FULLSCREEN:
+                if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
+                    // At least one of the split-screen TaskFragment that covers this one is
+                    // translucent.
+                    // When in split mode, home will be reparented to the secondary split while
+                    // leaving TaskFragments not supporting split below. Due to
+                    // TaskDisplayArea#assignRootTaskOrdering always adjusts home surface layer to
+                    // the bottom, this makes sure TaskFragments not in split roots won't occlude
+                    // home task unexpectedly.
+                    return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+                }
+                break;
+            case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+                if (gotTranslucentSplitScreenPrimary) {
+                    // Covered by translucent primary split-screen on top.
+                    return TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+                }
+                break;
+            case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
+                if (gotTranslucentSplitScreenSecondary) {
+                    // Covered by translucent secondary split-screen on top.
+                    return TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+                }
+                break;
+        }
+
+        // Lastly - check if there is a translucent fullscreen TaskFragment on top.
+        return gotTranslucentFullscreen
+                ? TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
+                : TASK_FRAGMENT_VISIBILITY_VISIBLE;
+    }
+
+    private static boolean hasRunningActivity(WindowContainer wc) {
+        if (wc.asTaskFragment() != null) {
+            return wc.asTaskFragment().topRunningActivity() != null;
+        }
+        return wc.asActivityRecord() != null && !wc.asActivityRecord().finishing;
+    }
+
+    private static boolean isTranslucent(WindowContainer wc, ActivityRecord starting) {
+        if (wc.asTaskFragment() != null) {
+            return wc.asTaskFragment().isTranslucent(starting);
+        } else if (wc.asActivityRecord() != null) {
+            return !wc.asActivityRecord().occludesParent();
+        }
+        return false;
+    }
+
+
+    private boolean isTopActivityLaunchedBehind() {
+        final ActivityRecord top = topRunningActivity();
+        return top != null && top.mLaunchTaskBehind;
+    }
+
+    final void updateActivityVisibilities(@Nullable ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
+        mTaskSupervisor.beginActivityVisibilityUpdate();
+        try {
+            mEnsureActivitiesVisibleHelper.process(
+                    starting, configChanges, preserveWindows, notifyClients);
+        } finally {
+            mTaskSupervisor.endActivityVisibilityUpdate();
+        }
+    }
+
+    final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
+            boolean deferPause) {
+        ActivityRecord next = topRunningActivity(true /* focusableOnly */);
+        if (next == null || !next.canResumeByCompat()) {
+            return false;
+        }
+
+        next.delayedResume = false;
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
+
+        // If the top activity is the resumed one, nothing to do.
+        if (mResumedActivity == next && next.isState(RESUMED)
+                && taskDisplayArea.allResumedActivitiesComplete()) {
+            // Make sure we have executed any pending transitions, since there
+            // should be nothing left to do at this point.
+            executeAppTransition(options);
+            // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
+            // we still want to check if the visibility of other windows have changed (e.g. bringing
+            // a fullscreen window forward to cover another freeform activity.)
+            if (taskDisplayArea.inMultiWindowMode()) {
+                taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+                        false /* preserveWindows */, true /* notifyClients */);
+            }
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
+                    + "resumed %s", next);
+            return false;
+        }
+
+        // If we are currently pausing an activity, then don't do anything until that is done.
+        final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
+        if (!allPausedComplete) {
+            ProtoLog.v(WM_DEBUG_STATES,
+                    "resumeTopActivity: Skip resume: some activity pausing.");
+            return false;
+        }
+
+        // If we are sleeping, and there is no resumed activity, and the top activity is paused,
+        // well that is the state we want.
+        if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
+            // Make sure we have executed any pending transitions, since there
+            // should be nothing left to do at this point.
+            executeAppTransition(options);
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and"
+                    + " all paused");
+            return false;
+        }
+
+        // Make sure that the user who owns this activity is started.  If not,
+        // we will just leave it as is because someone should be bringing
+        // another user's activities to the top of the stack.
+        if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
+            Slog.w(TAG, "Skipping resume of top activity " + next
+                    + ": user " + next.mUserId + " is stopped");
+            return false;
+        }
+
+        // The activity may be waiting for stop, but that is no longer
+        // appropriate for it.
+        mTaskSupervisor.mStoppingActivities.remove(next);
+
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
+
+        mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);
+
+        ActivityRecord lastResumed = null;
+        final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
+        if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) {
+            // So, why aren't we using prev here??? See the param comment on the method. prev
+            // doesn't represent the last resumed activity. However, the last focus stack does if
+            // it isn't null.
+            lastResumed = lastFocusedRootTask.getTopResumedActivity();
+        }
+
+        boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
+        if (mResumedActivity != null) {
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
+            pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
+                    next, "resumeTopActivity");
+        }
+        if (pausing) {
+            ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
+                    + " start pausing");
+            // At this point we want to put the upcoming activity's process
+            // at the top of the LRU list, since we know we will be needing it
+            // very soon and it would be a waste to let it get killed if it
+            // happens to be sitting towards the end.
+            if (next.attachedToProcess()) {
+                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+                        true /* activityChange */, false /* updateOomAdj */,
+                        false /* addPendingTopUid */);
+            } else if (!next.isProcessRunning()) {
+                // Since the start-process is asynchronous, if we already know the process of next
+                // activity isn't running, we can start the process earlier to save the time to wait
+                // for the current activity to be paused.
+                final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
+                mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
+                        isTop ? "pre-top-activity" : "pre-activity");
+            }
+            if (lastResumed != null) {
+                lastResumed.setWillCloseOrEnterPip(true);
+            }
+            return true;
+        } else if (mResumedActivity == next && next.isState(RESUMED)
+                && taskDisplayArea.allResumedActivitiesComplete()) {
+            // It is possible for the activity to be resumed when we paused back stacks above if the
+            // next activity doesn't have to wait for pause to complete.
+            // So, nothing else to-do except:
+            // Make sure we have executed any pending transitions, since there
+            // should be nothing left to do at this point.
+            executeAppTransition(options);
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed "
+                    + "(dontWaitForPause) %s", next);
+            return true;
+        }
+
+        // If the most recent activity was noHistory but was only stopped rather
+        // than stopped+finished because the device went to sleep, we need to make
+        // sure to finish it as we're making a new activity topmost.
+        if (shouldSleepActivities()) {
+            mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
+        }
+
+        if (prev != null && prev != next && next.nowVisible) {
+            // The next activity is already visible, so hide the previous
+            // activity's windows right now so we can show the new one ASAP.
+            // We only do this if the previous is finishing, which should mean
+            // it is on top of the one being resumed so hiding it quickly
+            // is good.  Otherwise, we want to do the normal route of allowing
+            // the resumed activity to be shown so we can decide if the
+            // previous should actually be hidden depending on whether the
+            // new one is found to be full-screen or not.
+            if (prev.finishing) {
+                prev.setVisibility(false);
+                if (DEBUG_SWITCH) {
+                    Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev
+                            + ", nowVisible=" + next.nowVisible);
+                }
+            } else {
+                if (DEBUG_SWITCH) {
+                    Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev
+                            + ", nowVisible=" + next.nowVisible);
+                }
+            }
+        }
+
+        // Launching this app's activity, make sure the app is no longer
+        // considered stopped.
+        try {
+            mTaskSupervisor.getActivityMetricsLogger()
+                    .notifyBeforePackageUnstopped(next.packageName);
+            mAtmService.getPackageManager().setPackageStoppedState(
+                    next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
+        } catch (RemoteException e1) {
+        } catch (IllegalArgumentException e) {
+            Slog.w(TAG, "Failed trying to unstop package "
+                    + next.packageName + ": " + e);
+        }
+
+        // We are starting up the next activity, so tell the window manager
+        // that the previous one will be hidden soon.  This way it can know
+        // to ignore it when computing the desired screen orientation.
+        boolean anim = true;
+        final DisplayContent dc = taskDisplayArea.mDisplayContent;
+        if (prev != null) {
+            if (prev.finishing) {
+                if (DEBUG_TRANSITION) {
+                    Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev);
+                }
+                if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
+                    anim = false;
+                    dc.prepareAppTransition(TRANSIT_NONE);
+                } else {
+                    dc.prepareAppTransition(TRANSIT_CLOSE);
+                }
+                prev.setVisibility(false);
+            } else {
+                if (DEBUG_TRANSITION) {
+                    Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev);
+                }
+                if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
+                    anim = false;
+                    dc.prepareAppTransition(TRANSIT_NONE);
+                } else {
+                    dc.prepareAppTransition(TRANSIT_OPEN,
+                            next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
+                }
+            }
+        } else {
+            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
+            if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
+                anim = false;
+                dc.prepareAppTransition(TRANSIT_NONE);
+            } else {
+                dc.prepareAppTransition(TRANSIT_OPEN);
+            }
+        }
+
+        if (anim) {
+            next.applyOptionsAnimation();
+        } else {
+            next.abortAndClearOptionsAnimation();
+        }
+
+        mTaskSupervisor.mNoAnimActivities.clear();
+
+        if (next.attachedToProcess()) {
+            if (DEBUG_SWITCH) {
+                Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.stopped
+                        + " visibleRequested=" + next.mVisibleRequested);
+            }
+
+            // If the previous activity is translucent, force a visibility update of
+            // the next activity, so that it's added to WM's opening app list, and
+            // transition animation can be set up properly.
+            // For example, pressing Home button with a translucent activity in focus.
+            // Launcher is already visible in this case. If we don't add it to opening
+            // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
+            // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
+            final boolean lastActivityTranslucent = lastFocusedRootTask != null
+                    && (lastFocusedRootTask.inMultiWindowMode()
+                    || (lastFocusedRootTask.mLastPausedActivity != null
+                    && !lastFocusedRootTask.mLastPausedActivity.occludesParent()));
+
+            // This activity is now becoming visible.
+            if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
+                next.setVisibility(true);
+            }
+
+            // schedule launch ticks to collect information about slow apps.
+            next.startLaunchTickingLocked();
+
+            ActivityRecord lastResumedActivity =
+                    lastFocusedRootTask == null ? null
+                            : lastFocusedRootTask.getTopResumedActivity();
+            final ActivityRecord.State lastState = next.getState();
+
+            mAtmService.updateCpuStats();
+
+            ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
+
+            next.setState(RESUMED, "resumeTopActivity");
+
+            // Have the window manager re-evaluate the orientation of
+            // the screen based on the new activity order.
+            boolean notUpdated = true;
+
+            // Activity should also be visible if set mLaunchTaskBehind to true (see
+            // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
+            if (shouldBeVisible(next)) {
+                // We have special rotation behavior when here is some active activity that
+                // requests specific orientation or Keyguard is locked. Make sure all activity
+                // visibilities are set correctly as well as the transition is updated if needed
+                // to get the correct rotation behavior. Otherwise the following call to update
+                // the orientation may cause incorrect configurations delivered to client as a
+                // result of invisible window resize.
+                // TODO: Remove this once visibilities are set correctly immediately when
+                // starting an activity.
+                notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
+                        true /* markFrozenIfConfigChanged */, false /* deferResume */);
+            }
+
+            if (notUpdated) {
+                // The configuration update wasn't able to keep the existing
+                // instance of the activity, and instead started a new one.
+                // We should be all done, but let's just make sure our activity
+                // is still at the top and schedule another run if something
+                // weird happened.
+                ActivityRecord nextNext = topRunningActivity();
+                ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
+                        + "%s, new next: %s", next, nextNext);
+                if (nextNext != next) {
+                    // Do over!
+                    mTaskSupervisor.scheduleResumeTopActivities();
+                }
+                if (!next.mVisibleRequested || next.stopped) {
+                    next.setVisibility(true);
+                }
+                next.completeResumeLocked();
+                return true;
+            }
+
+            try {
+                final ClientTransaction transaction =
+                        ClientTransaction.obtain(next.app.getThread(), next.appToken);
+                // Deliver all pending results.
+                ArrayList<ResultInfo> a = next.results;
+                if (a != null) {
+                    final int size = a.size();
+                    if (!next.finishing && size > 0) {
+                        if (DEBUG_RESULTS) {
+                            Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
+                        }
+                        transaction.addCallback(ActivityResultItem.obtain(a));
+                    }
+                }
+
+                if (next.newIntents != null) {
+                    transaction.addCallback(
+                            NewIntentItem.obtain(next.newIntents, true /* resume */));
+                }
+
+                // Well the app will no longer be stopped.
+                // Clear app token stopped state in window manager if needed.
+                next.notifyAppResumed(next.stopped);
+
+                EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
+                        next.getTask().mTaskId, next.shortComponentName);
+
+                mAtmService.getAppWarningsLocked().onResumeActivity(next);
+                next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
+                next.abortAndClearOptionsAnimation();
+                transaction.setLifecycleStateRequest(
+                        ResumeActivityItem.obtain(next.app.getReportedProcState(),
+                                dc.isNextTransitionForward()));
+                mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+
+                ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
+            } catch (Exception e) {
+                // Whoops, need to restart this activity!
+                ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
+                        + "%s", lastState, next);
+                next.setState(lastState, "resumeTopActivityInnerLocked");
+
+                // lastResumedActivity being non-null implies there is a lastStack present.
+                if (lastResumedActivity != null) {
+                    lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
+                }
+
+                Slog.i(TAG, "Restarting because process died: " + next);
+                if (!next.hasBeenLaunched) {
+                    next.hasBeenLaunched = true;
+                } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
+                        && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
+                    next.showStartingWindow(false /* taskSwitch */);
+                }
+                mTaskSupervisor.startSpecificActivity(next, true, false);
+                return true;
+            }
+
+            // From this point on, if something goes wrong there is no way
+            // to recover the activity.
+            try {
+                next.completeResumeLocked();
+            } catch (Exception e) {
+                // If any exception gets thrown, toss away this
+                // activity and try the next one.
+                Slog.w(TAG, "Exception thrown during resume of " + next, e);
+                next.finishIfPossible("resume-exception", true /* oomAdj */);
+                return true;
+            }
+        } else {
+            // Whoops, need to restart this activity!
+            if (!next.hasBeenLaunched) {
+                next.hasBeenLaunched = true;
+            } else {
+                if (SHOW_APP_STARTING_PREVIEW) {
+                    next.showStartingWindow(false /* taskSwich */);
+                }
+                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
+            }
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
+            mTaskSupervisor.startSpecificActivity(next, true, true);
+        }
+
+        return true;
+    }
+
+    boolean shouldSleepOrShutDownActivities() {
+        return shouldSleepActivities() || mAtmService.mShuttingDown;
+    }
+
+    /**
+     * Returns true if the TaskFragment should be visible.
+     *
+     * @param starting The currently starting activity or null if there is none.
+     */
+    boolean shouldBeVisible(ActivityRecord starting) {
+        return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+    }
+
+    final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) {
+        return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
+    }
+
+    /**
+     * Start pausing the currently resumed activity.  It is an error to call this if there
+     * is already an activity being paused or there is no resumed activity.
+     *
+     * @param userLeaving True if this should result in an onUserLeaving to the current activity.
+     * @param uiSleeping True if this is happening with the user interface going to sleep (the
+     * screen turning off).
+     * @param resuming The activity we are currently trying to resume or null if this is not being
+     *                 called as part of resuming the top activity, so we shouldn't try to instigate
+     *                 a resume here if not null.
+     * @param reason The reason of pausing the activity.
+     * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
+     * it to tell us when it is done.
+     */
+    boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
+            String reason) {
+        if (!hasDirectChildActivities()) {
+            return false;
+        }
+
+        ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,
+                mResumedActivity);
+
+        if (mPausingActivity != null) {
+            Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+                    + " state=" + mPausingActivity.getState());
+            if (!shouldSleepActivities()) {
+                // Avoid recursion among check for sleep and complete pause during sleeping.
+                // Because activity will be paused immediately after resume, just let pause
+                // be completed by the order of activity paused from clients.
+                completePause(false, resuming);
+            }
+        }
+        ActivityRecord prev = mResumedActivity;
+
+        if (prev == null) {
+            if (resuming == null) {
+                Slog.wtf(TAG, "Trying to pause when nothing is resumed");
+                mRootWindowContainer.resumeFocusedTasksTopActivities();
+            }
+            return false;
+        }
+
+        if (prev == resuming) {
+            Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
+            return false;
+        }
+
+        ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
+        mPausingActivity = prev;
+        mLastPausedActivity = prev;
+        if (prev.isNoHistory() && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
+            mTaskSupervisor.mNoHistoryActivities.add(prev);
+        }
+        prev.setState(PAUSING, "startPausingLocked");
+        prev.getTask().touchActiveTime();
+
+        mAtmService.updateCpuStats();
+
+        boolean pauseImmediately = false;
+        boolean shouldAutoPip = false;
+        if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) {
+            // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
+            // activity to be paused, while at the same time resuming the new resume activity
+            // only if the previous activity can't go into Pip since we want to give Pip
+            // activities a chance to enter Pip before resuming the next activity.
+            final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState(
+                    "shouldResumeWhilePausing", userLeaving);
+            if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+                shouldAutoPip = true;
+            } else if (!lastResumedCanPip) {
+                pauseImmediately = true;
+            } else {
+                // The previous activity may still enter PIP even though it did not allow auto-PIP.
+            }
+        }
+
+        boolean didAutoPip = false;
+        if (prev.attachedToProcess()) {
+            if (shouldAutoPip) {
+                ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
+                        + "directly: %s", prev);
+
+                didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
+                mPausingActivity = null;
+            } else {
+                ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
+                try {
+                    EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
+                            prev.shortComponentName, "userLeaving=" + userLeaving, reason);
+
+                    mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
+                            prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
+                                    prev.configChangeFlags, pauseImmediately));
+                } catch (Exception e) {
+                    // Ignore exception, if process died other code will cleanup.
+                    Slog.w(TAG, "Exception thrown during pause", e);
+                    mPausingActivity = null;
+                    mLastPausedActivity = null;
+                    mTaskSupervisor.mNoHistoryActivities.remove(prev);
+                }
+            }
+        } else {
+            mPausingActivity = null;
+            mLastPausedActivity = null;
+            mTaskSupervisor.mNoHistoryActivities.remove(prev);
+        }
+
+        // If we are not going to sleep, we want to ensure the device is
+        // awake until the next activity is started.
+        if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) {
+            mTaskSupervisor.acquireLaunchWakelock();
+        }
+
+        // If already entered PIP mode, no need to keep pausing.
+        if (mPausingActivity != null && !didAutoPip) {
+            // Have the window manager pause its key dispatching until the new
+            // activity has started.  If we're pausing the activity just because
+            // the screen is being turned off and the UI is sleeping, don't interrupt
+            // key dispatch; the same activity will pick it up again on wakeup.
+            if (!uiSleeping) {
+                prev.pauseKeyDispatchingLocked();
+            } else {
+                ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
+            }
+
+            if (pauseImmediately) {
+                // If the caller said they don't want to wait for the pause, then complete
+                // the pause now.
+                completePause(false, resuming);
+                return false;
+
+            } else {
+                prev.schedulePauseTimeout();
+                return true;
+            }
+
+        } else {
+            // This activity either failed to schedule the pause or it entered PIP mode,
+            // so just treat it as being paused now.
+            ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next.");
+            if (resuming == null) {
+                mRootWindowContainer.resumeFocusedTasksTopActivities();
+            }
+            return false;
+        }
+    }
+
+    @VisibleForTesting
+    void completePause(boolean resumeNext, ActivityRecord resuming) {
+        // Complete the pausing process of a pausing activity, so it doesn't make sense to
+        // operate on non-leaf tasks.
+        // warnForNonLeafTask("completePauseLocked");
+
+        ActivityRecord prev = mPausingActivity;
+        ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
+
+        if (prev != null) {
+            prev.setWillCloseOrEnterPip(false);
+            final boolean wasStopping = prev.isState(STOPPING);
+            prev.setState(PAUSED, "completePausedLocked");
+            if (prev.finishing) {
+                // We will update the activity visibility later, no need to do in
+                // completeFinishing(). Updating visibility here might also making the next
+                // activities to be resumed, and could result in wrong app transition due to
+                // lack of previous activity information.
+                ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
+                prev = prev.completeFinishing(false /* updateVisibility */,
+                        "completePausedLocked");
+            } else if (prev.hasProcess()) {
+                ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
+                                + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
+                        prev.mVisibleRequested);
+                if (prev.deferRelaunchUntilPaused) {
+                    // Complete the deferred relaunch that was waiting for pause to complete.
+                    ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
+                    prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
+                } else if (wasStopping) {
+                    // We are also stopping, the stop request must have gone soon after the pause.
+                    // We can't clobber it, because the stop confirmation will not be handled.
+                    // We don't need to schedule another stop, we only need to let it happen.
+                    prev.setState(STOPPING, "completePausedLocked");
+                } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) {
+                    // Clear out any deferred client hide we might currently have.
+                    prev.setDeferHidingClient(false);
+                    // If we were visible then resumeTopActivities will release resources before
+                    // stopping.
+                    prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */,
+                            "completePauseLocked");
+                }
+            } else {
+                ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
+                prev = null;
+            }
+            // It is possible the activity was freezing the screen before it was paused.
+            // In that case go ahead and remove the freeze this activity has on the screen
+            // since it is no longer visible.
+            if (prev != null) {
+                prev.stopFreezingScreenLocked(true /*force*/);
+            }
+            mPausingActivity = null;
+        }
+
+        if (resumeNext) {
+            final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
+            if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
+                mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev, null);
+            } else {
+                // checkReadyForSleep();
+                final ActivityRecord top =
+                        topRootTask != null ? topRootTask.topRunningActivity() : null;
+                if (top == null || (prev != null && top != prev)) {
+                    // If there are no more activities available to run, do resume anyway to start
+                    // something. Also if the top activity on the root task is not the just paused
+                    // activity, we need to go ahead and resume it to ensure we complete an
+                    // in-flight app switch.
+                    mRootWindowContainer.resumeFocusedTasksTopActivities();
+                }
+            }
+        }
+
+        if (prev != null) {
+            prev.resumeKeyDispatchingLocked();
+        }
+
+        mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
+
+        // Notify when the task stack has changed, but only if visibilities changed (not just
+        // focus). Also if there is an active root pinned task - we always want to notify it about
+        // task stack changes, because its positioning may depend on it.
+        if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause
+                || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) {
+            mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
+            mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
+        }
+    }
+
+    @Override
+    void forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) {
+        final int count = mChildren.size();
+        boolean isLeafTaskFrag = true;
+        if (traverseTopToBottom) {
+            for (int i = count - 1; i >= 0; --i) {
+                final TaskFragment child = mChildren.get(i).asTaskFragment();
+                if (child != null) {
+                    isLeafTaskFrag = false;
+                    child.forAllLeafTaskFragments(callback, traverseTopToBottom);
+                }
+            }
+        } else {
+            for (int i = 0; i < count; i++) {
+                final TaskFragment child = mChildren.get(i).asTaskFragment();
+                if (child != null) {
+                    isLeafTaskFrag = false;
+                    child.forAllLeafTaskFragments(callback, traverseTopToBottom);
+                }
+            }
+        }
+        if (isLeafTaskFrag) callback.accept(this);
+    }
+
+    @Override
+    boolean forAllLeafTaskFragments(Function<TaskFragment, Boolean> callback) {
+        boolean isLeafTaskFrag = true;
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final TaskFragment child = mChildren.get(i).asTaskFragment();
+            if (child != null) {
+                isLeafTaskFrag = false;
+                if (child.forAllLeafTaskFragments(callback)) {
+                    return true;
+                }
+            }
+        }
+        if (isLeafTaskFrag) {
+            return callback.apply(this);
+        }
+        return false;
+    }
+
+    void addChild(ActivityRecord r) {
+        addChild(r, POSITION_TOP);
+    }
+
+    @Override
+    void addChild(WindowContainer child, int index) {
+        boolean isAddingActivity = child.asActivityRecord() != null;
+        final Task task = isAddingActivity ? getTask() : null;
+
+        // If this task had any child before we added this one.
+        boolean taskHadChild = task != null && task.hasChild();
+        // getActivityType() looks at the top child, so we need to read the type before adding
+        // a new child in case the new child is on top and UNDEFINED.
+        final int activityType = task != null ? task.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
+
+        super.addChild(child, index);
+
+        if (isAddingActivity && task != null) {
+            child.asActivityRecord().inHistory = true;
+            task.onDescendantActivityAdded(taskHadChild, activityType, child.asActivityRecord());
+        }
+    }
+
+    void executeAppTransition(ActivityOptions options) {
+        // No app transition applied to the task fragment.
+    }
+
+    boolean shouldSleepActivities() {
+        return false;
+    }
+
+    @Override
+    void resolveOverrideConfiguration(Configuration newParentConfig) {
+        mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
+        super.resolveOverrideConfiguration(newParentConfig);
+
+        int windowingMode =
+                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
+        final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+
+        // Resolve override windowing mode to fullscreen for home task (even on freeform
+        // display), or split-screen if in split-screen mode.
+        if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
+            windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode)
+                    ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN;
+            getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
+        }
+
+        // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in
+        // pinned windowing mode.
+        if (!supportsMultiWindow()) {
+            final int candidateWindowingMode =
+                    windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
+            if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
+                    && candidateWindowingMode != WINDOWING_MODE_PINNED) {
+                getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
+                        WINDOWING_MODE_FULLSCREEN);
+            }
+        }
+
+        if (isLeafTaskFragment()) {
+            resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */);
+        }
+        computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+    }
+
+    boolean supportsMultiWindow() {
+        return supportsMultiWindowInDisplayArea(getDisplayArea());
+    }
+
+    /**
+     * @return whether this task supports multi-window if it is in the given
+     *         {@link TaskDisplayArea}.
+     */
+    boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) {
+        if (!mAtmService.mSupportsMultiWindow) {
+            return false;
+        }
+        final Task task = getTask();
+        if (task == null) {
+            return false;
+        }
+        if (tda == null) {
+            Slog.w(TAG, "Can't find TaskDisplayArea to determine support for multi"
+                    + " window. Task id=" + getTaskId() + " attached=" + isAttached());
+            return false;
+        }
+        if (!getTask().isResizeable() && !tda.supportsNonResizableMultiWindow()) {
+            // Not support non-resizable in multi window.
+            return false;
+        }
+
+        return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight);
+    }
+
+    private int getTaskId() {
+        return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID;
+    }
+
+    private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
+            Rect previousBounds) {
+
+        int windowingMode =
+                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+        }
+        // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old
+        // mode that may cause the bounds to be miscalculated, e.g. letterboxed.
+        getConfiguration().windowConfiguration.setWindowingMode(windowingMode);
+        Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+        if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            // Use empty bounds to indicate "fill parent".
+            outOverrideBounds.setEmpty();
+            // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
+            // the parent or display is smaller than the size, the content may be cropped.
+            return;
+        }
+
+        adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
+        if (windowingMode == WINDOWING_MODE_FREEFORM) {
+            computeFreeformBounds(outOverrideBounds, newParentConfig);
+            return;
+        }
+    }
+
+    /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
+    private void computeFreeformBounds(@NonNull Rect outBounds,
+            @NonNull Configuration newParentConfig) {
+        // by policy, make sure the window remains within parent somewhere
+        final float density =
+                ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
+        final Rect parentBounds =
+                new Rect(newParentConfig.windowConfiguration.getBounds());
+        final DisplayContent display = getDisplayContent();
+        if (display != null) {
+            // If a freeform window moves below system bar, there is no way to move it again
+            // by touch. Because its caption is covered by system bar. So we exclude them
+            // from root task bounds. and then caption will be shown inside stable area.
+            final Rect stableBounds = new Rect();
+            display.getStableRect(stableBounds);
+            parentBounds.intersect(stableBounds);
+        }
+
+        fitWithinBounds(outBounds, parentBounds,
+                (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
+                (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
+
+        // Prevent to overlap caption with stable insets.
+        final int offsetTop = parentBounds.top - outBounds.top;
+        if (offsetTop > 0) {
+            outBounds.offset(0, offsetTop);
+        }
+    }
+
+    /**
+     * Adjusts bounds to stay within root task bounds.
+     *
+     * Since bounds might be outside of root task bounds, this method tries to move the bounds in
+     * a way that keep them unchanged, but be contained within the root task bounds.
+     *
+     * @param bounds Bounds to be adjusted.
+     * @param rootTaskBounds Bounds within which the other bounds should remain.
+     * @param overlapPxX The amount of px required to be visible in the X dimension.
+     * @param overlapPxY The amount of px required to be visible in the Y dimension.
+     */
+    private static void fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX,
+            int overlapPxY) {
+        if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) {
+            return;
+        }
+
+        // For each side of the parent (eg. left), check if the opposing side of the window (eg.
+        // right) is at least overlap pixels away. If less, offset the window by that difference.
+        int horizontalDiff = 0;
+        // If window is smaller than overlap, use it's smallest dimension instead
+        int overlapLR = Math.min(overlapPxX, bounds.width());
+        if (bounds.right < (rootTaskBounds.left + overlapLR)) {
+            horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left);
+        } else if (bounds.left > (rootTaskBounds.right - overlapLR)) {
+            horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left));
+        }
+        int verticalDiff = 0;
+        int overlapTB = Math.min(overlapPxY, bounds.width());
+        if (bounds.bottom < (rootTaskBounds.top + overlapTB)) {
+            verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top);
+        } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) {
+            verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top));
+        }
+        bounds.offset(horizontalDiff, verticalDiff);
+    }
+
+    /**
+     * Ensures all visible activities at or below the input activity have the right configuration.
+     */
+    void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
+        mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
+    }
+
+    void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
+            @NonNull Configuration parentConfig) {
+        int minWidth = mMinWidth;
+        int minHeight = mMinHeight;
+        // If the task has no requested minimal size, we'd like to enforce a minimal size
+        // so that the user can not render the task fragment too small to manipulate. We don't need
+        // to do this for the root pinned task as the bounds are controlled by the system.
+        if (!inPinnedWindowingMode()) {
+            final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
+            final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+            final int defaultMinSize = (int) (defaultMinSizeDp * density);
+
+            if (minWidth == INVALID_MIN_SIZE) {
+                minWidth = defaultMinSize;
+            }
+            if (minHeight == INVALID_MIN_SIZE) {
+                minHeight = defaultMinSize;
+            }
+        }
+        if (bounds.isEmpty()) {
+            // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
+            // do, we can just skip.
+            final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
+            if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
+                return;
+            }
+            bounds.set(parentBounds);
+        }
+        final boolean adjustWidth = minWidth > bounds.width();
+        final boolean adjustHeight = minHeight > bounds.height();
+        if (!(adjustWidth || adjustHeight)) {
+            return;
+        }
+
+        if (adjustWidth) {
+            if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
+                bounds.left = bounds.right - minWidth;
+            } else {
+                // Either left bounds match, or neither match, or the previous bounds were
+                // fullscreen and we default to keeping left.
+                bounds.right = bounds.left + minWidth;
+            }
+        }
+        if (adjustHeight) {
+            if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
+                bounds.top = bounds.bottom - minHeight;
+            } else {
+                // Either top bounds match, or neither match, or the previous bounds were
+                // fullscreen and we default to keeping top.
+                bounds.bottom = bounds.top + minHeight;
+            }
+        }
+    }
+
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig) {
+        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+                null /* compatInsets */);
+    }
+
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
+        if (overrideDisplayInfo != null) {
+            // Make sure the screen related configs can be computed by the provided display info.
+            inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
+            invalidateAppBoundsConfig(inOutConfig);
+        }
+        computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
+                null /* compatInsets */);
+    }
+
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig,
+            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+        if (compatInsets != null) {
+            // Make sure the app bounds can be computed by the compat insets.
+            invalidateAppBoundsConfig(inOutConfig);
+        }
+        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+                compatInsets);
+    }
+
+    /**
+     * Forces the app bounds related configuration can be computed by
+     * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
+     * ActivityRecord.CompatDisplayInsets)}.
+     */
+    private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
+        final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
+        if (appBounds != null) {
+            appBounds.setEmpty();
+        }
+        inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+        inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+    }
+
+    /**
+     * Calculates configuration values used by the client to get resources. This should be run
+     * using app-facing bounds (bounds unmodified by animations or transient interactions).
+     *
+     * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
+     * configuring an "inherit-bounds" window which means that all configuration settings would
+     * just be inherited from the parent configuration.
+     **/
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
+            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
+        }
+
+        float density = inOutConfig.densityDpi;
+        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+            density = parentConfig.densityDpi;
+        }
+        density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+
+        // The bounds may have been overridden at this level. If the parent cannot cover these
+        // bounds, the configuration is still computed according to the override bounds.
+        final boolean insideParentBounds;
+
+        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
+        final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
+        if (resolvedBounds == null || resolvedBounds.isEmpty()) {
+            mTmpFullBounds.set(parentBounds);
+            insideParentBounds = true;
+        } else {
+            mTmpFullBounds.set(resolvedBounds);
+            insideParentBounds = parentBounds.contains(resolvedBounds);
+        }
+
+        // Non-null compatibility insets means the activity prefers to keep its original size, so
+        // out bounds doesn't need to be restricted by the parent or current display
+        final boolean customContainerPolicy = compatInsets != null;
+
+        Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+        if (outAppBounds == null || outAppBounds.isEmpty()) {
+            // App-bounds hasn't been overridden, so calculate a value for it.
+            inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
+            outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+
+            if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
+                final Rect containingAppBounds;
+                if (insideParentBounds) {
+                    containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
+                } else {
+                    // Restrict appBounds to display non-decor rather than parent because the
+                    // override bounds are beyond the parent. Otherwise, it won't match the
+                    // overridden bounds.
+                    final TaskDisplayArea displayArea = getDisplayArea();
+                    containingAppBounds = displayArea != null
+                            ? displayArea.getWindowConfiguration().getAppBounds() : null;
+                }
+                if (containingAppBounds != null && !containingAppBounds.isEmpty()) {
+                    outAppBounds.intersect(containingAppBounds);
+                }
+            }
+        }
+
+        if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
+                || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+            if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
+                mTmpNonDecorBounds.set(mTmpFullBounds);
+                mTmpStableBounds.set(mTmpFullBounds);
+            } else if (!customContainerPolicy
+                    && (overrideDisplayInfo != null || getDisplayContent() != null)) {
+                final DisplayInfo di = overrideDisplayInfo != null
+                        ? overrideDisplayInfo
+                        : getDisplayContent().getDisplayInfo();
+
+                // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
+                // area, i.e. the screen area without the system bars.
+                // The non decor inset are areas that could never be removed in Honeycomb. See
+                // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
+                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
+            } else {
+                // Apply the given non-decor and stable insets to calculate the corresponding bounds
+                // for screen size of configuration.
+                int rotation = inOutConfig.windowConfiguration.getRotation();
+                if (rotation == ROTATION_UNDEFINED) {
+                    rotation = parentConfig.windowConfiguration.getRotation();
+                }
+                if (rotation != ROTATION_UNDEFINED && customContainerPolicy) {
+                    mTmpNonDecorBounds.set(mTmpFullBounds);
+                    mTmpStableBounds.set(mTmpFullBounds);
+                    compatInsets.getBoundsByRotation(mTmpBounds, rotation);
+                    intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
+                            compatInsets.mNonDecorInsets[rotation]);
+                    intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
+                            compatInsets.mStableInsets[rotation]);
+                    outAppBounds.set(mTmpNonDecorBounds);
+                } else {
+                    // Set to app bounds because it excludes decor insets.
+                    mTmpNonDecorBounds.set(outAppBounds);
+                    mTmpStableBounds.set(outAppBounds);
+                }
+            }
+
+            if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+                final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+                inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
+                        ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
+                        : overrideScreenWidthDp;
+            }
+            if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+                final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+                inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
+                        ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
+                        : overrideScreenHeightDp;
+            }
+
+            if (inOutConfig.smallestScreenWidthDp
+                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
+                if (WindowConfiguration.isFloating(windowingMode)) {
+                    // For floating tasks, calculate the smallest width from the bounds of the task
+                    inOutConfig.smallestScreenWidthDp = (int) (
+                            Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
+                }
+                // otherwise, it will just inherit
+            }
+        }
+
+        if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+            inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+                    ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+        }
+        if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
+            // For calculating screen layout, we need to use the non-decor inset screen area for the
+            // calculation for compatibility reasons, i.e. screen area without system bars that
+            // could never go away in Honeycomb.
+            int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
+            int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+            // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
+            // undefined so it can't be used.
+            if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+                compatScreenWidthDp = inOutConfig.screenWidthDp;
+            }
+            if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+                compatScreenHeightDp = inOutConfig.screenHeightDp;
+            }
+            // Reducing the screen layout starting from its parent config.
+            inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
+                    compatScreenWidthDp, compatScreenHeightDp);
+        }
+    }
+
+    /**
+     * Gets bounds with non-decor and stable insets applied respectively.
+     *
+     * If bounds overhangs the display, those edges will not get insets. See
+     * {@link #intersectWithInsetsIfFits}
+     *
+     * @param outNonDecorBounds where to place bounds with non-decor insets applied.
+     * @param outStableBounds where to place bounds with stable insets applied.
+     * @param bounds the bounds to inset.
+     */
+    void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
+            DisplayInfo displayInfo) {
+        outNonDecorBounds.set(bounds);
+        outStableBounds.set(bounds);
+        final Task rootTask = getRootTaskFragment().asTask();
+        if (rootTask == null || rootTask.mDisplayContent == null) {
+            return;
+        }
+        mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+
+        final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
+        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
+                displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
+        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
+
+        policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
+        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
+    }
+
+    /**
+     * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
+     * intersectBounds on a side, then the respective side will not be intersected.
+     *
+     * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
+     * inset on that side is no-longer applicable. This scenario happens when a task's minimal
+     * bounds are larger than the provided parent/display bounds.
+     *
+     * @param inOutBounds the bounds to intersect.
+     * @param intersectBounds the bounds to intersect with.
+     * @param intersectInsets insets to apply to intersectBounds before intersecting.
+     */
+    static void intersectWithInsetsIfFits(
+            Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
+        if (inOutBounds.right <= intersectBounds.right) {
+            inOutBounds.right =
+                    Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
+        }
+        if (inOutBounds.bottom <= intersectBounds.bottom) {
+            inOutBounds.bottom =
+                    Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
+        }
+        if (inOutBounds.left >= intersectBounds.left) {
+            inOutBounds.left =
+                    Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
+        }
+        if (inOutBounds.top >= intersectBounds.top) {
+            inOutBounds.top =
+                    Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
+        }
+    }
+
+    /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */
+    static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp,
+            int screenHeightDp) {
+        sourceScreenLayout = sourceScreenLayout
+                & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
+        final int longSize = Math.max(screenWidthDp, screenHeightDp);
+        final int shortSize = Math.min(screenWidthDp, screenHeightDp);
+        return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
+    }
+
+    @Override
+    public int getActivityType() {
+        final int applicationType = super.getActivityType();
+        if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
+            return applicationType;
+        }
+        return getTopChild().getActivityType();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        super.onConfigurationChanged(newParentConfig);
+
+        if (mTaskFragmentOrganizer != null) {
+            // Parent config may have changed. The controller will check if there is any important
+            // config change for the organizer.
+            mTaskFragmentOrganizerController
+                    .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this);
+            mTaskFragmentOrganizerController
+                    .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
+        }
+    }
+
+    // TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment
+    private void sendTaskFragmentAppeared() {
+        if (mTaskFragmentOrganizer != null) {
+            mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
+        }
+    }
+
+    // TODO(b/190433129) call when TaskFragment is removed from WCT#deleteTaskFragment
+    private void sendTaskFragmentVanished() {
+        if (mTaskFragmentOrganizer != null) {
+            mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this);
+        }
+    }
+
+    /**
+     * Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be
+     * called from {@link Task}.
+     */
+    TaskFragmentInfo getTaskFragmentInfo() {
+        return new TaskFragmentInfo(
+                mFragmentToken,
+                mInitialComponentName,
+                mRemoteToken.toWindowContainerToken(),
+                getConfiguration(),
+                getChildCount() == 0,
+                isVisible());
+    }
+
+    @Nullable
+    IBinder getFragmentToken() {
+        return mFragmentToken;
+    }
+
+    boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+            boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) {
+        boolean printed = false;
+        Runnable headerPrinter = () -> {
+            if (needSep) {
+                pw.println();
+            }
+            if (header != null) {
+                header.run();
+            }
+
+            dumpInner(prefix, pw, dumpAll, dumpPackage);
+        };
+
+        if (dumpPackage == null) {
+            // If we are not filtering by package, we want to print absolutely everything,
+            // so always print the header even if there are no tasks/activities inside.
+            headerPrinter.run();
+            headerPrinter = null;
+            printed = true;
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            WindowContainer child = mChildren.get(i);
+            if (child.asTaskFragment() != null) {
+                printed |= child.asTaskFragment().dump(prefix + "      ", fd, pw, dumpAll,
+                        dumpClient, dumpPackage, needSep, headerPrinter);
+            } else if (child.asActivityRecord() != null) {
+                ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "      ",
+                        "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter,
+                        getTask());
+            }
+        }
+
+        return printed;
+    }
+
+    void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
+        pw.print(prefix); pw.print("* "); pw.println(this);
+        pw.println(prefix + "  mBounds=" + getRequestedOverrideBounds());
+    }
+
+    @Override
+    void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(HASH_CODE, System.identityHashCode(this));
+        final ActivityRecord topActivity = topRunningActivity();
+        proto.write(USER_ID, topActivity != null ? topActivity.mUserId : USER_NULL);
+        proto.write(TITLE, topActivity != null ? topActivity.intent.getComponent()
+                .flattenToShortString() : "TaskFragment");
+        proto.end(token);
+    }
+
+    @Override
+    long getProtoFieldId() {
+        return TASK_FRAGMENT;
+    }
+
+    @Override
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
+            @WindowTraceLogLevel int logLevel) {
+        if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
+            return;
+        }
+
+        final long token = proto.start(fieldId);
+
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
+
+        proto.write(DISPLAY_ID, getDisplayId());
+        proto.write(ACTIVITY_TYPE, getActivityType());
+        proto.write(MIN_WIDTH, mMinWidth);
+        proto.write(MIN_HEIGHT, mMinHeight);
+
+        proto.end(token);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
new file mode 100644
index 0000000..31175b7
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
+
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.view.SurfaceControl;
+import android.window.ITaskFragmentOrganizer;
+import android.window.ITaskFragmentOrganizerController;
+import android.window.TaskFragmentAppearedInfo;
+import android.window.TaskFragmentInfo;
+
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * Stores and manages the client {@link android.window.TaskFragmentOrganizer}.
+ */
+public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerController.Stub {
+    private static final String TAG = "TaskFragmentOrganizerController";
+
+    private final ActivityTaskManagerService mAtmService;
+    private final WindowManagerGlobalLock mGlobalLock;
+    private final Set<ITaskFragmentOrganizer> mOrganizers = new ArraySet<>();
+    private final Map<ITaskFragmentOrganizer, DeathRecipient> mDeathRecipients = new ArrayMap<>();
+    private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
+            new WeakHashMap<>();
+    private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
+            new WeakHashMap<>();
+
+    private class DeathRecipient implements IBinder.DeathRecipient {
+        final ITaskFragmentOrganizer mOrganizer;
+
+        DeathRecipient(ITaskFragmentOrganizer organizer) {
+            mOrganizer = organizer;
+        }
+
+        @Override
+        public void binderDied() {
+            removeOrganizer(mOrganizer);
+        }
+    }
+
+    TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
+        mAtmService = atm;
+        mGlobalLock = atm.mGlobalLock;
+    }
+
+    @Override
+    public void registerOrganizer(ITaskFragmentOrganizer organizer) {
+        final int pid = Binder.getCallingPid();
+        final long uid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                        "Register task fragment organizer=%s uid=%d pid=%d",
+                        organizer.asBinder(), uid, pid);
+                if (mOrganizers.contains(organizer)) {
+                    throw new IllegalStateException(
+                            "Replacing existing organizer currently unsupported");
+                }
+
+                final DeathRecipient dr = new DeathRecipient(organizer);
+                try {
+                    organizer.asBinder().linkToDeath(dr, 0);
+                } catch (RemoteException e) {
+                    // Oh well...
+                }
+
+                mOrganizers.add(organizer);
+                mDeathRecipients.put(organizer, dr);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void unregisterOrganizer(ITaskFragmentOrganizer organizer) {
+        final int pid = Binder.getCallingPid();
+        final long uid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                        "Unregister task fragment organizer=%s uid=%d pid=%d",
+                        organizer.asBinder(), uid, pid);
+                if (!mOrganizers.contains(organizer)) {
+                    throw new IllegalStateException(
+                            "The task fragment organizer hasn't been registered.");
+                }
+
+                final DeathRecipient dr = mDeathRecipients.get(organizer);
+                organizer.asBinder().unlinkToDeath(dr, 0);
+
+                removeOrganizer(organizer);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+        validateOrganizer(organizer);
+
+        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
+        final TaskFragmentInfo info = tf.getTaskFragmentInfo();
+        final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
+                "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
+        try {
+            organizer.onTaskFragmentAppeared(
+                    new TaskFragmentAppearedInfo(info, outSurfaceControl));
+            mLastSentTaskFragmentInfos.put(tf, info);
+        } catch (RemoteException e) {
+            // Oh well...
+        }
+    }
+
+    void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+        validateOrganizer(organizer);
+
+        // Check if the info is different from the last reported info.
+        final TaskFragmentInfo info = tf.getTaskFragmentInfo();
+        final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
+        if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
+                info.getConfiguration(), lastInfo.getConfiguration())) {
+            return;
+        }
+
+        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName());
+        try {
+            organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
+            mLastSentTaskFragmentInfos.put(tf, info);
+        } catch (RemoteException e) {
+            // Oh well...
+        }
+    }
+
+    void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+        validateOrganizer(organizer);
+
+        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
+        try {
+            organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
+        } catch (RemoteException e) {
+            // Oh well...
+        }
+        mLastSentTaskFragmentInfos.remove(tf);
+        mLastSentTaskFragmentParentConfigs.remove(tf);
+    }
+
+    void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+        validateOrganizer(organizer);
+
+        // Check if the parent info is different from the last reported parent info.
+        if (tf.getParent() == null || tf.getParent().asTask() == null) {
+            mLastSentTaskFragmentParentConfigs.remove(tf);
+            return;
+        }
+        final Task parent = tf.getParent().asTask();
+        final Configuration parentConfig = parent.getConfiguration();
+        final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf);
+        if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) {
+            return;
+        }
+
+        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                "TaskFragment parent info changed name=%s parentTaskId=%d",
+                tf.getName(), parent.mTaskId);
+        try {
+            organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
+            mLastSentTaskFragmentParentConfigs.put(tf, parentConfig);
+        } catch (RemoteException e) {
+            // Oh well...
+        }
+    }
+
+    private void removeOrganizer(ITaskFragmentOrganizer organizer) {
+        synchronized (mGlobalLock) {
+            mOrganizers.remove(organizer);
+            mDeathRecipients.remove(organizer);
+        }
+        // TODO(b/190432728) move child activities of organized TaskFragment to leaf Task
+    }
+
+    /**
+     * Makes sure that the organizer has been correctly registered to prevent any Sidecar
+     * implementation from organizing {@link TaskFragment} without registering first. In such case,
+     * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
+     * {@link TaskFragment} after the organizer process died.
+     */
+    private void validateOrganizer(ITaskFragmentOrganizer organizer) {
+        if (!mOrganizers.contains(organizer)) {
+            throw new IllegalArgumentException(
+                    "TaskFragmentOrganizer has not been registered. Organizer=" + organizer);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 3a2ca80..31d3a0f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -23,15 +23,13 @@
 import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
-import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
-import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
+import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.WindowConfiguration;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -69,13 +67,6 @@
 class TaskOrganizerController extends ITaskOrganizerController.Stub {
     private static final String TAG = "TaskOrganizerController";
 
-    /**
-     * Masks specifying which configurations are important to report back to an organizer when
-     * changed.
-     */
-    private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS;
-    private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS;
-
     // The set of modes that are currently supports
     // TODO: Remove once the task organizer can support all modes
     @VisibleForTesting
@@ -388,6 +379,15 @@
                                 mOrganizer.mTaskOrganizer, t);
                     }
                 }
+                if (mService.getTransitionController().isShellTransitionsEnabled()) {
+                    // dispose is only called outside of transitions (eg during unregister). Since
+                    // we "migrate" surfaces when replacing organizers, visibility gets delegated
+                    // to transitions; however, since there is no transition at this point, we have
+                    // to manually show the surface here.
+                    if (t.mTaskOrganizer != null && t.getSurfaceControl() != null) {
+                        t.getSyncTransaction().show(t.getSurfaceControl());
+                    }
+                }
             }
 
             // Remove organizer state after removing tasks so we get a chance to send
@@ -480,7 +480,8 @@
         final int uid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
-            synchronized (mGlobalLock) {
+            final ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
+            final Runnable withGlobalLock = () -> {
                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
                         organizer.asBinder(), uid);
                 if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
@@ -489,10 +490,10 @@
                             new TaskOrganizerState(organizer, uid));
                 }
 
-                final ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
                 mService.mRootWindowContainer.forAllTasks((task) -> {
-                    if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, task.getWindowingMode())) {
+                    if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES,
+                            task.getWindowingMode())) {
                         return;
                     }
 
@@ -502,11 +503,19 @@
                     if (returnTask) {
                         SurfaceControl outSurfaceControl = state.addTaskWithoutCallback(task,
                                 "TaskOrganizerController.registerTaskOrganizer");
-                        taskInfos.add(new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
+                        taskInfos.add(
+                                new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
                     }
                 });
-                return new ParceledListSlice<>(taskInfos);
+            };
+            if (mService.getTransitionController().isShellTransitionsEnabled()) {
+                mService.getTransitionController().mRunningLock.runWhenIdle(1000, withGlobalLock);
+            } else {
+                synchronized (mGlobalLock) {
+                    withGlobalLock.run();
+                }
             }
+            return new ParceledListSlice<>(taskInfos);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -518,7 +527,7 @@
         final int uid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
-            synchronized (mGlobalLock) {
+            final Runnable withGlobalLock = () -> {
                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
                 if (state == null) {
                     return;
@@ -527,6 +536,13 @@
                         organizer.asBinder(), uid);
                 state.unlinkDeath();
                 state.dispose();
+            };
+            if (mService.getTransitionController().isShellTransitionsEnabled()) {
+                mService.getTransitionController().mRunningLock.runWhenIdle(1000, withGlobalLock);
+            } else {
+                synchronized (mGlobalLock) {
+                    withGlobalLock.run();
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -765,18 +781,9 @@
         mTmpTaskInfo.configuration.unset();
         task.fillTaskInfo(mTmpTaskInfo);
 
-        boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo);
-        if (!changed) {
-            int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
-            final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
-                    ? (int) mTmpTaskInfo.configuration.windowConfiguration.diff(
-                            lastInfo.configuration.windowConfiguration,
-                            true /* compareUndefined */) : 0;
-            if ((winCfgChanges & REPORT_WINDOW_CONFIGS) == 0) {
-                cfgChanges &= ~ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
-            }
-            changed = (cfgChanges & REPORT_CONFIGS) != 0;
-        }
+        boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo)
+                || !configurationsAreEqualForOrganizer(
+                        mTmpTaskInfo.configuration, lastInfo.configuration);
         if (!(changed || force)) {
             // mTmpTaskInfo will be reused next time.
             return;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0cd09807..8e18da14 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -16,11 +16,13 @@
 
 package com.android.server.wm;
 
-
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -124,9 +126,16 @@
     /** The final animation targets derived from participants after promotion. */
     private ArraySet<WindowContainer> mTargets = null;
 
+    private TransitionInfo.AnimationOptions mOverrideOptions;
+
     private @TransitionState int mState = STATE_COLLECTING;
     private boolean mReadyCalled = false;
 
+    // TODO(b/188595497): remove when not needed.
+    /** @see RecentsAnimationController#mNavigationBarAttachedToApp */
+    private boolean mNavBarAttachedToApp = false;
+    private int mNavBarDisplayId = INVALID_DISPLAY;
+
     Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags,
             TransitionController controller, BLASTSyncEngine syncEngine) {
         mType = type;
@@ -136,6 +145,10 @@
         mSyncId = mSyncEngine.startSyncSet(this);
     }
 
+    void addFlag(int flag) {
+        mFlags |= flag;
+    }
+
     @VisibleForTesting
     int getSyncId() {
         return mSyncId;
@@ -207,6 +220,15 @@
     }
 
     /**
+     * Set animation options for collecting transition by ActivityRecord.
+     * @param options AnimationOptions captured from ActivityOptions
+     */
+    void setOverrideAnimation(TransitionInfo.AnimationOptions options) {
+        if (mSyncId < 0) return;
+        mOverrideOptions = options;
+    }
+
+    /**
      * Call this when all known changes related to this transition have been applied. Until
      * all participants have finished drawing, the transition can still collect participants.
      *
@@ -275,12 +297,28 @@
         }
 
         // Commit all going-invisible containers
+        boolean activitiesWentInvisible = false;
         for (int i = 0; i < mParticipants.size(); ++i) {
             final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
-            if (ar != null && !ar.isVisibleRequested()) {
-                ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
-                        "  Commit activity becoming invisible: %s", ar);
-                ar.commitVisibility(false /* visible */, false /* performLayout */);
+            if (ar != null) {
+                if (!ar.isVisibleRequested()) {
+                    // If activity is capable of entering PiP, give it a chance to enter it now.
+                    if (ar.getDeferHidingClient() && ar.getTask() != null) {
+                        mController.mAtm.mTaskSupervisor.mUserLeaving = true;
+                        ar.getTaskFragment().startPausing(false /* uiSleeping */,
+                                null /* resuming */, "finishTransition");
+                        mController.mAtm.mTaskSupervisor.mUserLeaving = false;
+                    }
+                    ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                            "  Commit activity becoming invisible: %s", ar);
+                    ar.commitVisibility(false /* visible */, false /* performLayout */);
+                    activitiesWentInvisible = true;
+                }
+                if (mChanges.get(ar).mVisible != ar.isVisibleRequested()) {
+                    // Legacy dispatch relies on this (for now).
+                    ar.mEnteringAnimation = ar.isVisibleRequested();
+                }
+                mController.dispatchLegacyAppTransitionFinished(ar);
             }
             final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
             if (wt != null && !wt.isVisibleRequested()) {
@@ -289,6 +327,14 @@
                 wt.commitVisibility(false /* visible */);
             }
         }
+        if (activitiesWentInvisible) {
+            // Always schedule stop processing when transition finishes because activities don't
+            // stop while they are in a transition thus their stop could still be pending.
+            mController.mAtm.mTaskSupervisor
+                    .scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+        }
+
+        legacyRestoreNavigationBarFromApp();
     }
 
     void abort() {
@@ -297,6 +343,7 @@
         if (mState != STATE_COLLECTING) {
             throw new IllegalStateException("Too late to abort.");
         }
+        mController.dispatchLegacyAppTransitionCancelled();
         mState = STATE_ABORT;
         // Syncengine abort will call through to onTransactionReady()
         mSyncEngine.abort(mSyncId);
@@ -327,6 +374,7 @@
             mController.mAtm.mRootWindowContainer.getDisplayContent(displayId)
                     .getPendingTransaction().merge(transaction);
             mSyncId = -1;
+            mOverrideOptions = null;
             return;
         }
 
@@ -340,6 +388,10 @@
         // Resolve the animating targets from the participants
         mTargets = calculateTargets(mParticipants, mChanges);
         final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
+        info.setAnimationOptions(mOverrideOptions);
+
+        // TODO(b/188669821): Move to animation impl in shell.
+        handleLegacyRecentsStartBehavior(displayId, info);
 
         handleNonAppWindowsInTransition(displayId, mType, mFlags);
 
@@ -360,6 +412,7 @@
         mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
         buildFinishTransaction(mFinishTransaction, info.getRootLeash());
         if (mController.getTransitionPlayer() != null) {
+            mController.dispatchLegacyAppTransitionStarting(info);
             try {
                 ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                         "Calling onTransitionReady: %s", info);
@@ -375,6 +428,7 @@
             cleanUpOnFailure();
         }
         mSyncId = -1;
+        mOverrideOptions = null;
     }
 
     /**
@@ -394,6 +448,100 @@
         finishTransition();
     }
 
+    /** @see RecentsAnimationController#attachNavigationBarToApp */
+    private void handleLegacyRecentsStartBehavior(int displayId, TransitionInfo info) {
+        if ((mFlags & TRANSIT_FLAG_IS_RECENTS) == 0) {
+            return;
+        }
+        final DisplayContent dc =
+                mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
+        if (dc == null || !dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
+                // Skip the case where the nav bar is controlled by fade rotation.
+                || dc.getFadeRotationAnimationController() != null) {
+            return;
+        }
+
+        WindowContainer topWC = null;
+        // Find the top-most non-home, closing app.
+        for (int i = 0; i < info.getChanges().size(); ++i) {
+            final TransitionInfo.Change c = info.getChanges().get(i);
+            if (c.getTaskInfo() == null || c.getTaskInfo().displayId != displayId
+                    || c.getTaskInfo().getActivityType() != ACTIVITY_TYPE_STANDARD
+                    || !(c.getMode() == TRANSIT_CLOSE || c.getMode() == TRANSIT_TO_BACK)) {
+                continue;
+            }
+            topWC = WindowContainer.fromBinder(c.getContainer().asBinder());
+            break;
+        }
+        if (topWC == null || topWC.inMultiWindowMode()) {
+            return;
+        }
+
+        final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar();
+        if (navWindow == null || navWindow.mToken == null) {
+            return;
+        }
+        mNavBarAttachedToApp = true;
+        mNavBarDisplayId = displayId;
+        navWindow.mToken.cancelAnimation();
+        final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
+        final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
+        t.reparent(navSurfaceControl, topWC.getSurfaceControl());
+        t.show(navSurfaceControl);
+
+        final WindowContainer imeContainer = dc.getImeContainer();
+        if (imeContainer.isVisible()) {
+            t.setRelativeLayer(navSurfaceControl, imeContainer.getSurfaceControl(), 1);
+        } else {
+            // Place the nav bar on top of anything else in the top activity.
+            t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
+        }
+        if (mController.mStatusBar != null) {
+            mController.mStatusBar.setNavigationBarLumaSamplingEnabled(displayId, false);
+        }
+    }
+
+    /** @see RecentsAnimationController#restoreNavigationBarFromApp */
+    void legacyRestoreNavigationBarFromApp() {
+        if (!mNavBarAttachedToApp) return;
+        mNavBarAttachedToApp = false;
+
+        if (mController.mStatusBar != null) {
+            mController.mStatusBar.setNavigationBarLumaSamplingEnabled(mNavBarDisplayId, true);
+        }
+
+        final DisplayContent dc =
+                mController.mAtm.mRootWindowContainer.getDisplayContent(mNavBarDisplayId);
+        final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar();
+        if (navWindow == null) return;
+        navWindow.setSurfaceTranslationY(0);
+
+        final WindowToken navToken = navWindow.mToken;
+        if (navToken == null) return;
+        final SurfaceControl.Transaction t = dc.getPendingTransaction();
+        final WindowContainer parent = navToken.getParent();
+        t.setLayer(navToken.getSurfaceControl(), navToken.getLastLayer());
+
+        boolean animate = false;
+        // Search for the home task. If it is supposed to be visible, then the navbar is not at
+        // the bottom of the screen, so we need to animate it.
+        for (int i = 0; i < mTargets.size(); ++i) {
+            final Task task = mTargets.valueAt(i).asTask();
+            if (task == null || !task.isHomeOrRecentsRootTask()) continue;
+            animate = task.isVisibleRequested();
+            break;
+        }
+
+        if (animate) {
+            final NavBarFadeAnimationController controller =
+                    new NavBarFadeAnimationController(dc);
+            controller.fadeWindowToken(true);
+        } else {
+            // Reparent the SurfaceControl of nav bar token back.
+            t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+        }
+    }
+
     private void handleNonAppWindowsInTransition(int displayId,
             @WindowManager.TransitionType int transit, int flags) {
         final DisplayContent dc =
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index cc63c49..3186aea 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -17,6 +17,12 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OPEN;
 
 import android.annotation.NonNull;
@@ -24,14 +30,18 @@
 import android.app.ActivityManager;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.util.Slog;
 import android.view.WindowManager;
 import android.window.IRemoteTransition;
 import android.window.ITransitionPlayer;
+import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
 
 import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.util.ArrayList;
 
@@ -44,12 +54,17 @@
     private ITransitionPlayer mTransitionPlayer;
     final ActivityTaskManagerService mAtm;
 
+    private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners =
+            new ArrayList<>();
+
     /**
      * Currently playing transitions (in the order they were started). When finished, records are
      * removed from this list.
      */
     private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>();
 
+    final Lock mRunningLock = new Lock();
+
     private final IBinder.DeathRecipient mTransitionPlayerDeath = () -> {
         // clean-up/finish any playing transitions.
         for (int i = 0; i < mPlayingTransitions.size(); ++i) {
@@ -57,13 +72,18 @@
         }
         mPlayingTransitions.clear();
         mTransitionPlayer = null;
+        mRunningLock.doNotifyLocked();
     };
 
     /** The transition currently being constructed (collecting participants). */
     private Transition mCollectingTransition = null;
 
+    // TODO(b/188595497): remove when not needed.
+    final StatusBarManagerInternal mStatusBar;
+
     TransitionController(ActivityTaskManagerService atm) {
         mAtm = atm;
+        mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
     }
 
     /** @see #createTransition(int, int) */
@@ -87,6 +107,7 @@
         mCollectingTransition = new Transition(type, flags, this, mAtm.mWindowManager.mSyncEngine);
         ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating Transition: %s",
                 mCollectingTransition);
+        dispatchLegacyAppTransitionPending();
         return mCollectingTransition;
     }
 
@@ -240,6 +261,12 @@
         mCollectingTransition.collectExistenceChange(wc);
     }
 
+    /** @see Transition#setOverrideAnimation */
+    void setOverrideAnimation(TransitionInfo.AnimationOptions options) {
+        if (mCollectingTransition == null) return;
+        mCollectingTransition.setOverrideAnimation(options);
+    }
+
     /** @see Transition#setReady */
     void setReady(boolean ready) {
         if (mCollectingTransition == null) return;
@@ -261,6 +288,7 @@
         ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Finish Transition: %s", record);
         mPlayingTransitions.remove(record);
         record.finishTransition();
+        mRunningLock.doNotifyLocked();
     }
 
     void moveToPlaying(Transition transition) {
@@ -279,4 +307,97 @@
         mCollectingTransition = null;
     }
 
+    /**
+     * Explicitly mark the collectingTransition as being part of recents gesture. Used for legacy
+     * behaviors.
+     * TODO(b/188669821): Remove once legacy recents behavior is moved to shell.
+     */
+    void setIsLegacyRecents() {
+        if (mCollectingTransition == null) return;
+        mCollectingTransition.addFlag(TRANSIT_FLAG_IS_RECENTS);
+    }
+
+    void legacyDetachNavigationBarFromApp(@NonNull IBinder token) {
+        final Transition transition = Transition.fromBinder(token);
+        if (transition == null || !mPlayingTransitions.contains(transition)) {
+            Slog.e(TAG, "Transition isn't playing: " + token);
+            return;
+        }
+        transition.legacyRestoreNavigationBarFromApp();
+    }
+
+    void registerLegacyListener(WindowManagerInternal.AppTransitionListener listener) {
+        mLegacyListeners.add(listener);
+    }
+
+    void dispatchLegacyAppTransitionPending() {
+        for (int i = 0; i < mLegacyListeners.size(); ++i) {
+            mLegacyListeners.get(i).onAppTransitionPendingLocked();
+        }
+    }
+
+    void dispatchLegacyAppTransitionStarting(TransitionInfo info) {
+        final boolean keyguardGoingAway = info.getType() == TRANSIT_KEYGUARD_GOING_AWAY
+                || (info.getFlags() & (TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE
+                        | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION
+                        | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER
+                        | TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION)) != 0;
+        for (int i = 0; i < mLegacyListeners.size(); ++i) {
+            mLegacyListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway,
+                    0 /* durationHint */, SystemClock.uptimeMillis(),
+                    AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
+        }
+    }
+
+    void dispatchLegacyAppTransitionFinished(ActivityRecord ar) {
+        for (int i = 0; i < mLegacyListeners.size(); ++i) {
+            mLegacyListeners.get(i).onAppTransitionFinishedLocked(ar.token);
+        }
+    }
+
+    void dispatchLegacyAppTransitionCancelled() {
+        for (int i = 0; i < mLegacyListeners.size(); ++i) {
+            mLegacyListeners.get(i).onAppTransitionCancelledLocked(
+                    false /* keyguardGoingAway */);
+        }
+    }
+
+    class Lock {
+        private int mTransitionWaiters = 0;
+        void runWhenIdle(long timeout, Runnable r) {
+            synchronized (mAtm.mGlobalLock) {
+                if (!inTransition()) {
+                    r.run();
+                    return;
+                }
+                mTransitionWaiters += 1;
+            }
+            final long startTime = SystemClock.uptimeMillis();
+            final long endTime = startTime + timeout;
+            while (true) {
+                synchronized (mAtm.mGlobalLock) {
+                    if (!inTransition() || SystemClock.uptimeMillis() > endTime) {
+                        mTransitionWaiters -= 1;
+                        r.run();
+                        return;
+                    }
+                }
+                synchronized (this) {
+                    try {
+                        this.wait(timeout);
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        void doNotifyLocked() {
+            synchronized (this) {
+                if (mTransitionWaiters > 0) {
+                    this.notifyAll();
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b1c7e19..7b8cfc4 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1671,6 +1671,15 @@
         return false;
     }
 
+    boolean forAllLeafTaskFragments(Function<TaskFragment, Boolean> callback) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            if (mChildren.get(i).forAllLeafTaskFragments(callback)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * For all root tasks at or below this container call the callback.
      *
@@ -1739,6 +1748,19 @@
         }
     }
 
+    void forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) {
+        final int count = mChildren.size();
+        if (traverseTopToBottom) {
+            for (int i = count - 1; i >= 0; --i) {
+                mChildren.get(i).forAllLeafTaskFragments(callback, traverseTopToBottom);
+            }
+        } else {
+            for (int i = 0; i < count; i++) {
+                mChildren.get(i).forAllLeafTaskFragments(callback, traverseTopToBottom);
+            }
+        }
+    }
+
     /**
      * For all root tasks at or below this container call the callback.
      *
@@ -3075,6 +3097,11 @@
     }
 
     /** Cheap way of doing cast and instanceof. */
+    TaskFragment asTaskFragment() {
+        return null;
+    }
+
+    /** Cheap way of doing cast and instanceof. */
     WindowToken asWindowToken() {
         return null;
     }
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index ffd6d21..baea854 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -89,6 +89,11 @@
     final Rect mCompatFrame = new Rect();
 
     /**
+     * {@code true} if the window frame is a simulated frame and attached to a decor window.
+     */
+    boolean mIsSimulatingDecorWindow = false;
+
+    /**
      * Whether the parent frame would have been different if there was no display cutout.
      */
     private boolean mParentFrameWasClippedByDisplayCutout;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 47087cf..f2a926c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -40,6 +40,7 @@
 import com.android.server.policy.WindowManagerPolicy;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Window manager local system service interface.
@@ -54,17 +55,18 @@
      */
     public interface AccessibilityControllerInternal {
         /**
-         * Enable the accessibility trace logging.
+         * Start tracing for the given logging types.
+         * @param loggingTypeFlags flags of the logging types enabled.
          */
-        void startTrace();
+        void startTrace(long loggingTypeFlags);
 
         /**
-         * Disable the accessibility trace logging.
+         * Disable accessibility tracing for all logging types.
          */
         void stopTrace();
 
         /**
-         * Is trace enabled or not.
+         * Is tracing enabled for any logging type.
          */
         boolean isAccessibilityTracingEnabled();
 
@@ -73,20 +75,23 @@
          *
          * @param where A string to identify this log entry, which can be used to filter/search
          *        through the tracing file.
+         * @param loggingTypeFlags The flags for the logging types this log entry belongs to.
          * @param callingParams The parameters for the method to be logged.
          * @param a11yDump The proto byte array for a11y state when the entry is generated.
          * @param callingUid The calling uid.
          * @param stackTrace The stack trace, null if not needed.
+         * @param ignoreStackEntries The stack entries can be removed
          */
         void logTrace(
-                String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] stackTrace);
+                String where, long loggingTypeFlags, String callingParams, byte[] a11yDump,
+                int callingUid, StackTraceElement[] stackTrace, Set<String> ignoreStackEntries);
 
         /**
          * Add an accessibility trace entry.
          *
          * @param where A string to identify this log entry, which can be used to filter/search
          *        through the tracing file.
+         * @param loggingTypeFlags The flags for the logging types this log entry belongs to.
          * @param callingParams The parameters for the method to be logged.
          * @param a11yDump The proto byte array for a11y state when the entry is generated.
          * @param callingUid The calling uid.
@@ -94,9 +99,11 @@
          * @param timeStamp The time when the method to be logged is called.
          * @param processId The calling process Id.
          * @param threadId The calling thread Id.
+         * @param ignoreStackEntries The stack entries can be removed
          */
-        void logTrace(String where, String callingParams, byte[] a11yDump, int callingUid,
-                StackTraceElement[] callStack, long timeStamp, int processId, long threadId);
+        void logTrace(String where, long loggingTypeFlags, String callingParams,
+                byte[] a11yDump, int callingUid, StackTraceElement[] callStack, long timeStamp,
+                int processId, long threadId, Set<String> ignoreStackEntries);
     }
 
     /**
@@ -115,6 +122,16 @@
          */
         void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
                 IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);
+
+        /**
+         * Called when the display is reparented and becomes an embedded
+         * display. The {@link WindowsForAccessibilityCallback} with the given embedded
+         * display will be replaced by the {@link WindowsForAccessibilityCallback}
+         * associated with its parent display at the same time.
+         *
+         * @param embeddedDisplayId The embedded display Id.
+         */
+        void onDisplayReparented(int embeddedDisplayId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 147260b..dc39bf9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -47,6 +47,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -1807,7 +1808,8 @@
             winAnimator.mEnterAnimationPending = true;
             winAnimator.mEnteringAnimation = true;
             // Check if we need to prepare a transition for replacing window first.
-            if (activity != null && activity.isVisible()
+            if (mAtmService.getTransitionController().getTransitionPlayer() == null
+                    && activity != null && activity.isVisible()
                     && !prepareWindowReplacementTransition(activity)) {
                 // If not, check if need to set up a dummy transition during display freeze
                 // so that the unfreeze wait for the apps to draw. This might be needed if
@@ -2481,7 +2483,7 @@
             if (win.mActivityRecord != null) {
                 win.mActivityRecord.updateReportedVisibilityLocked();
             }
-            if (displayPolicy.areSystemBarsForcedShownLw(win)) {
+            if (displayPolicy.areSystemBarsForcedShownLw()) {
                 result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
             }
             if (!win.isGoneForLayout()) {
@@ -2527,7 +2529,8 @@
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             }
             if (winAnimator.mSurfaceController != null) {
-                win.calculateSurfaceBounds(win.getAttrs(), mTmpRect);
+                win.calculateSurfaceBounds(win.getLayoutingAttrs(
+                        win.getWindowConfiguration().getRotation()), mTmpRect);
                 outSurfaceSize.set(mTmpRect.width(), mTmpRect.height());
             }
             getInsetsSourceControls(win, outActiveControls);
@@ -5404,6 +5407,25 @@
         }
     }
 
+    void setSandboxDisplayApis(int displayId, boolean sandboxDisplayApis) {
+        if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
+        }
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+                if (displayContent != null) {
+                    displayContent.setSandboxDisplayApis(sandboxDisplayApis);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     /** The global settings only apply to default display. */
     private boolean applyForcedPropertiesForDefaultDisplay() {
         boolean changed = false;
@@ -7585,6 +7607,7 @@
         public void registerAppTransitionListener(AppTransitionListener listener) {
             synchronized (mGlobalLock) {
                 getDefaultDisplayContentLocked().mAppTransition.registerListenerLocked(listener);
+                mAtmService.getTransitionController().registerLegacyListener(listener);
             }
         }
 
@@ -7854,7 +7877,10 @@
         @Override
         public boolean isTouchOrFaketouchDevice() {
             synchronized (mGlobalLock) {
-                // All touchable devices are also faketouchable.
+                if (mIsTouchDevice && !mIsFakeTouchDevice) {
+                    throw new IllegalStateException(
+                            "touchscreen supported device must report faketouch.");
+                }
                 return mIsFakeTouchDevice;
             }
         }
@@ -8570,7 +8596,7 @@
             }
 
             if (win.mActivityRecord == null || !win.mActivityRecord.isState(
-                    Task.ActivityState.RESUMED)) {
+                    ActivityRecord.State.RESUMED)) {
                 mDisplayHashController.sendDisplayHashError(callback,
                         DISPLAY_HASH_ERROR_MISSING_WINDOW);
                 return;
@@ -8625,4 +8651,23 @@
             return snapshot != null && snapshot.hasImeSurface();
         }
     }
+
+    @Override
+    public int getImeDisplayId() {
+        // TODO(b/189805422): Add a toast to notify users that IMS may get extra
+        //  onConfigurationChanged callback when perDisplayFocus is enabled.
+        //  Enabling perDisplayFocus means that we track focus on each display, so we don't have
+        //  the "top focus" display and getTopFocusedDisplayContent returns the default display
+        //  as the fallback. It leads to InputMethodService receives an extra onConfiguration
+        //  callback when InputMethodService move from a secondary display to another display
+        //  with the same display metrics because InputMethodService will always associate with
+        //  the ImeContainer on the default display in onCreate and receive a configuration update
+        //  to match default display ImeContainer and then receive another configuration update
+        //  from attachToWindowToken.
+        synchronized (mGlobalLock) {
+            final DisplayContent dc = mRoot.getTopFocusedDisplayContent();
+            return dc.getImePolicy() == DISPLAY_IME_POLICY_LOCAL ? dc.getDisplayId()
+                    : DEFAULT_DISPLAY;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index a94fd07..d596549 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -19,6 +19,12 @@
 import static android.os.Build.IS_USER;
 import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
 
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
+
+import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
@@ -36,6 +42,7 @@
 import com.android.internal.protolog.ProtoLogImpl;
 import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -58,10 +65,12 @@
 
     // Internal service impl -- must perform security checks before touching.
     private final WindowManagerService mInternal;
+    private final LetterboxConfiguration mLetterboxConfiguration;
 
     public WindowManagerShellCommand(WindowManagerService service) {
         mInterface = service;
         mInternal = service;
+        mLetterboxConfiguration = service.mLetterboxConfiguration;
     }
 
     @Override
@@ -113,6 +122,14 @@
                     return runGetIgnoreOrientationRequest(pw);
                 case "dump-visible-window-views":
                     return runDumpVisibleWindowViews(pw);
+                case "set-letterbox-style":
+                    return runSetLetterboxStyle(pw);
+                case "get-letterbox-style":
+                    return runGetLetterboxStyle(pw);
+                case "reset-letterbox-style":
+                    return runResetLetterboxStyle(pw);
+                case "set-sandbox-display-apis":
+                    return runSandboxDisplayApis(pw);
                 case "set-multi-window-config":
                     return runSetMultiWindowConfig();
                 case "get-multi-window-config":
@@ -331,6 +348,37 @@
         return 0;
     }
 
+    /**
+     * Override display size and metrics to reflect the DisplayArea of the calling activity.
+     */
+    private int runSandboxDisplayApis(PrintWriter pw) throws RemoteException {
+        int displayId = Display.DEFAULT_DISPLAY;
+        String arg = getNextArgRequired();
+        if ("-d".equals(arg)) {
+            displayId = Integer.parseInt(getNextArgRequired());
+            arg = getNextArgRequired();
+        }
+
+        final boolean sandboxDisplayApis;
+        switch (arg) {
+            case "true":
+            case "1":
+                sandboxDisplayApis = true;
+                break;
+            case "false":
+            case "0":
+                sandboxDisplayApis = false;
+                break;
+            default:
+                getErrPrintWriter().println("Error: expecting true, 1, false, 0, but we "
+                        + "get " + arg);
+                return -1;
+        }
+
+        mInternal.setSandboxDisplayApis(displayId, sandboxDisplayApis);
+        return 0;
+    }
+
     private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
         mInterface.dismissKeyguard(null /* callback */, null /* message */);
         return 0;
@@ -548,6 +596,231 @@
         return 0;
     }
 
+    private int runSetFixedOrientationLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
+        final float aspectRatio;
+        try {
+            String arg = getNextArgRequired();
+            aspectRatio = Float.parseFloat(arg);
+        } catch (NumberFormatException  e) {
+            getErrPrintWriter().println("Error: bad aspect ratio format " + e);
+            return -1;
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset' or aspect ratio should be provided as an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(aspectRatio);
+        }
+        return 0;
+    }
+
+    private int runSetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException {
+        final int cornersRadius;
+        try {
+            String arg = getNextArgRequired();
+            cornersRadius = Integer.parseInt(arg);
+        } catch (NumberFormatException  e) {
+            getErrPrintWriter().println("Error: bad corners radius format " + e);
+            return -1;
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset' or corners radius should be provided as an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxActivityCornersRadius(cornersRadius);
+        }
+        return 0;
+    }
+
+    private int runSetLetterboxBackgroundType(PrintWriter pw) throws RemoteException {
+        @LetterboxBackgroundType final int backgroundType;
+        try {
+            String arg = getNextArgRequired();
+            switch (arg) {
+                case "solid_color":
+                    backgroundType = LETTERBOX_BACKGROUND_SOLID_COLOR;
+                    break;
+                case "app_color_background":
+                    backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
+                    break;
+                case "app_color_background_floating":
+                    backgroundType = LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
+                    break;
+                case "wallpaper":
+                    backgroundType = LETTERBOX_BACKGROUND_WALLPAPER;
+                    break;
+                default:
+                    getErrPrintWriter().println(
+                            "Error: 'reset', 'solid_color', 'app_color_background' or "
+                            + "'wallpaper' should be provided as an argument");
+                    return -1;
+            }
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset', 'solid_color', 'app_color_background' or "
+                        + "'wallpaper' should be provided as an argument" + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxBackgroundType(backgroundType);
+        }
+        return 0;
+    }
+
+    private int runSetLetterboxBackgroundColor(PrintWriter pw) throws RemoteException {
+        final Color color;
+        try {
+            String arg = getNextArgRequired();
+            color = Color.valueOf(Color.parseColor(arg));
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset' or color in #RRGGBB format should be provided as "
+                            + "an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxBackgroundColor(color);
+        }
+        return 0;
+    }
+
+    private int runSetLetterboxBackgroundWallpaperBlurRadius(PrintWriter pw)
+            throws RemoteException {
+        final int radius;
+        try {
+            String arg = getNextArgRequired();
+            radius = Integer.parseInt(arg);
+        } catch (NumberFormatException  e) {
+            getErrPrintWriter().println("Error: blur radius format " + e);
+            return -1;
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset' or blur radius should be provided as an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxBackgroundWallpaperBlurRadius(radius);
+        }
+        return 0;
+    }
+
+    private int runSetLetterboxBackgroundWallpaperDarkScrimAlpha(PrintWriter pw)
+            throws RemoteException {
+        final float alpha;
+        try {
+            String arg = getNextArgRequired();
+            alpha = Float.parseFloat(arg);
+        } catch (NumberFormatException  e) {
+            getErrPrintWriter().println("Error: bad alpha format " + e);
+            return -1;
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset' or alpha should be provided as an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxBackgroundWallpaperDarkScrimAlpha(alpha);
+        }
+        return 0;
+    }
+
+    private int runSeLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
+        final float multiplier;
+        try {
+            String arg = getNextArgRequired();
+            multiplier = Float.parseFloat(arg);
+        } catch (NumberFormatException  e) {
+            getErrPrintWriter().println("Error: bad multiplier format " + e);
+            return -1;
+        } catch (IllegalArgumentException  e) {
+            getErrPrintWriter().println(
+                    "Error: 'reset' or multiplier should be provided as an argument " + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(multiplier);
+        }
+        return 0;
+    }
+
+    private int runSetLetterboxStyle(PrintWriter pw) throws RemoteException {
+        if (peekNextArg() == null) {
+            getErrPrintWriter().println("Error: No arguments provided.");
+        }
+        while (peekNextArg() != null) {
+            String arg = getNextArg();
+            switch (arg) {
+                case "--aspectRatio":
+                    runSetFixedOrientationLetterboxAspectRatio(pw);
+                    break;
+                case "--cornerRadius":
+                    runSetLetterboxActivityCornersRadius(pw);
+                    break;
+                case "--backgroundType":
+                    runSetLetterboxBackgroundType(pw);
+                    break;
+                case "--backgroundColor":
+                    runSetLetterboxBackgroundColor(pw);
+                    break;
+                case "--wallpaperBlurRadius":
+                    runSetLetterboxBackgroundWallpaperBlurRadius(pw);
+                    break;
+                case "--wallpaperDarkScrimAlpha":
+                    runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
+                    break;
+                case "--horizontalPositionMultiplier":
+                    runSeLetterboxHorizontalPositionMultiplier(pw);
+                    break;
+                default:
+                    getErrPrintWriter().println(
+                            "Error: Unrecognized letterbox style option: " + arg);
+                    return -1;
+            }
+        }
+        return 0;
+    }
+
+    private int runResetLetterboxStyle(PrintWriter pw) throws RemoteException {
+        if (peekNextArg() == null) {
+            resetLetterboxStyle();
+        }
+        synchronized (mInternal.mGlobalLock) {
+            while (peekNextArg() != null) {
+                String arg = getNextArg();
+                switch (arg) {
+                    case "aspectRatio":
+                        mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+                        break;
+                    case "cornerRadius":
+                        mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
+                        break;
+                    case "backgroundType":
+                        mLetterboxConfiguration.resetLetterboxBackgroundType();
+                        break;
+                    case "backgroundColor":
+                        mLetterboxConfiguration.resetLetterboxBackgroundColor();
+                        break;
+                    case "wallpaperBlurRadius":
+                        mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+                        break;
+                    case "wallpaperDarkScrimAlpha":
+                        mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+                        break;
+                    case "horizontalPositionMultiplier":
+                        mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+                        break;
+                    default:
+                        getErrPrintWriter().println(
+                                "Error: Unrecognized letterbox style option: " + arg);
+                        return -1;
+                }
+            }
+        }
+        return 0;
+    }
+
     private int runSetMultiWindowConfig() {
         if (peekNextArg() == null) {
             getErrPrintWriter().println("Error: No arguments provided.");
@@ -622,6 +895,40 @@
         return 0;
     }
 
+    private void resetLetterboxStyle() {
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+            mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
+            mLetterboxConfiguration.resetLetterboxBackgroundType();
+            mLetterboxConfiguration.resetLetterboxBackgroundColor();
+            mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+            mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
+            mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
+        }
+    }
+
+    private int runGetLetterboxStyle(PrintWriter pw) throws RemoteException {
+        synchronized (mInternal.mGlobalLock) {
+            pw.println("Corner radius: "
+                    + mLetterboxConfiguration.getLetterboxActivityCornersRadius());
+            pw.println("Horizontal position multiplier: "
+                    + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
+            pw.println("Aspect ratio: "
+                    + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
+
+            pw.println("Background type: "
+                    + LetterboxConfiguration.letterboxBackgroundTypeToString(
+                            mLetterboxConfiguration.getLetterboxBackgroundType()));
+            pw.println("    Background color: " + Integer.toHexString(
+                    mLetterboxConfiguration.getLetterboxBackgroundColor().toArgb()));
+            pw.println("    Wallpaper blur radius: "
+                    + mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius());
+            pw.println("    Wallpaper dark scrim alpha: "
+                    + mLetterboxConfiguration.getLetterboxBackgroundWallpaperDarkScrimAlpha());
+        }
+        return 0;
+    }
+
     private int runReset(PrintWriter pw) throws RemoteException {
         int displayId = getDisplayId(getNextArg());
 
@@ -646,6 +953,12 @@
         // set-ignore-orientation-request
         mInterface.setIgnoreOrientationRequest(displayId, false /* ignoreOrientationRequest */);
 
+        // set-letterbox-style
+        resetLetterboxStyle();
+
+        // set-sandbox-display-apis
+        mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true);
+
         // set-multi-window-config
         runResetMultiWindowConfig();
 
@@ -680,7 +993,12 @@
         pw.println("  set-ignore-orientation-request [-d DISPLAY_ID] [true|1|false|0]");
         pw.println("  get-ignore-orientation-request [-d DISPLAY_ID] ");
         pw.println("    If app requested orientation should be ignored.");
+        pw.println("  set-sandbox-display-apis [true|1|false|0]");
+        pw.println("    Sets override of Display APIs getRealSize / getRealMetrics to reflect ");
+        pw.println("    DisplayArea of the activity, or the window bounds if in letterbox or");
+        pw.println("    Size Compat Mode.");
 
+        printLetterboxHelp(pw);
         printMultiWindowConfigHelp(pw);
 
         pw.println("  reset [-d DISPLAY_ID]");
@@ -693,6 +1011,49 @@
         }
     }
 
+    private void printLetterboxHelp(PrintWriter pw) {
+        pw.println("  set-letterbox-style");
+        pw.println("    Sets letterbox style using the following options:");
+        pw.println("      --aspectRatio aspectRatio");
+        pw.println("        Aspect ratio of letterbox for fixed orientation. If aspectRatio <= "
+                + LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
+        pw.println("        both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will");
+        pw.println("        be ignored and framework implementation will determine aspect ratio.");
+        pw.println("      --cornerRadius radius");
+        pw.println("        Corners radius for activities in the letterbox mode. If radius < 0,");
+        pw.println("        both it and R.integer.config_letterboxActivityCornersRadius will be");
+        pw.println("        ignored and corners of the activity won't be rounded.");
+        pw.println("      --backgroundType [reset|solid_color|app_color_background");
+        pw.println("          |app_color_background_floating|wallpaper]");
+        pw.println("        Type of background used in the letterbox mode.");
+        pw.println("      --backgroundColor color");
+        pw.println("        Color of letterbox which is be used when letterbox background type");
+        pw.println("        is 'solid-color'. Use (set)get-letterbox-style to check and control");
+        pw.println("        letterbox background type. See Color#parseColor for allowed color");
+        pw.println("        formats (#RRGGBB and some colors by name, e.g. magenta or olive).");
+        pw.println("      --wallpaperBlurRadius radius");
+        pw.println("        Blur radius for 'wallpaper' letterbox background. If radius <= 0");
+        pw.println("        both it and R.dimen.config_letterboxBackgroundWallpaperBlurRadius");
+        pw.println("        are ignored and 0 is used.");
+        pw.println("      --wallpaperDarkScrimAlpha alpha");
+        pw.println("        Alpha of a black translucent scrim shown over 'wallpaper'");
+        pw.println("        letterbox background. If alpha < 0 or >= 1 both it and");
+        pw.println("        R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored");
+        pw.println("        and 0.0 (transparent) is used instead.");
+        pw.println("      --horizontalPositionMultiplier multiplier");
+        pw.println("        Horizontal position of app window center. If multiplier < 0 or > 1,");
+        pw.println("        both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
+        pw.println("        are ignored and central position (0.5) is used.");
+        pw.println("  reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
+        pw.println("      |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
+        pw.println("      |horizontalPositionMultiplier]");
+        pw.println("    Resets overrides to default values for specified properties separated");
+        pw.println("    by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
+        pw.println("    If no arguments provided, all values will be reset.");
+        pw.println("  get-letterbox-style");
+        pw.println("    Prints letterbox style configuration.");
+    }
+
     private void printMultiWindowConfigHelp(PrintWriter pw) {
         pw.println("  set-multi-window-config");
         pw.println("    Sets options to determine if activity should be shown in multi window:");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a82a478..3d36cc5 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,12 +17,17 @@
 package com.android.server.wm;
 
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
 import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
@@ -34,6 +39,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -46,10 +52,12 @@
 import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.IDisplayAreaOrganizerController;
+import android.window.ITaskFragmentOrganizerController;
 import android.window.ITaskOrganizerController;
 import android.window.ITransitionPlayer;
 import android.window.IWindowContainerTransactionCallback;
 import android.window.IWindowOrganizerController;
+import android.window.TaskFragmentCreationParams;
 import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -95,6 +103,7 @@
 
     final TaskOrganizerController mTaskOrganizerController;
     final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
+    final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
 
     final TransitionController mTransitionController;
 
@@ -103,6 +112,7 @@
         mGlobalLock = atm.mGlobalLock;
         mTaskOrganizerController = new TaskOrganizerController(mService);
         mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
+        mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm);
         mTransitionController = new TransitionController(atm);
     }
 
@@ -480,7 +490,7 @@
                 } else if (!task.mCreatedByOrganizer) {
                     throw new UnsupportedOperationException(
                             "Cannot set non-organized task as adjacent flag root: " + wc);
-                } else if (task.mAdjacentTask == null) {
+                } else if (task.getAdjacentTaskFragment() == null) {
                     throw new UnsupportedOperationException(
                             "Cannot set non-adjacent task as adjacent flag root: " + wc);
                 }
@@ -501,13 +511,15 @@
             return effects;
         }
 
+        final WindowContainer wc;
+        final IBinder fragmentToken;
         switch (type) {
             case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
                 effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
                 break;
             case HIERARCHY_OP_TYPE_REORDER:
             case HIERARCHY_OP_TYPE_REPARENT:
-                final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+                wc = WindowContainer.fromBinder(hop.getContainer());
                 if (wc == null || !wc.isAttached()) {
                     Slog.e(TAG, "Attempt to operate on detached container: " + wc);
                     break;
@@ -543,6 +555,40 @@
                 launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
                 mService.startActivityFromRecents(taskId, launchOpts);
                 break;
+            case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
+                final TaskFragmentCreationParams taskFragmentCreationOptions =
+                        hop.getTaskFragmentCreationOptions();
+                // TODO(b/190433129) add actual implementation on WM Core
+                break;
+            case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
+                wc = WindowContainer.fromBinder(hop.getContainer());
+                if (wc == null || !wc.isAttached()) {
+                    Slog.e(TAG, "Attempt to operate on detached container: " + wc);
+                    break;
+                }
+                final TaskFragment taskFragment = wc.asTaskFragment();
+                if (taskFragment == null || taskFragment.asTask() != null) {
+                    throw new IllegalArgumentException(
+                            "Can only delete organized TaskFragment, but not Task.");
+                }
+                // TODO(b/190433129) add actual implementation on WM Core
+                break;
+            case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
+                fragmentToken = hop.getContainer();
+                final Intent activityIntent = hop.getActivityIntent();
+                final Bundle activityOptions = hop.getLaunchOptions();
+                // TODO(b/190433129) add actual implementation on WM Core
+                break;
+            case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
+                fragmentToken = hop.getNewParent();
+                final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
+                // TODO(b/190433129) add actual implementation on WM Core
+                break;
+            case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
+                final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
+                final WindowContainer newParent = WindowContainer.fromBinder(hop.getNewParent());
+                // TODO(b/190433129) add actual implementation on WM Core
+                break;
         }
         return effects;
     }
@@ -704,13 +750,14 @@
     }
 
     private int setAdjacentRootsHierarchyOp(WindowContainerTransaction.HierarchyOp hop) {
-        final Task root1 = WindowContainer.fromBinder(hop.getContainer()).asTask();
-        final Task root2 = WindowContainer.fromBinder(hop.getAdjacentRoot()).asTask();
+        final TaskFragment root1 = WindowContainer.fromBinder(hop.getContainer()).asTaskFragment();
+        final TaskFragment root2 =
+                WindowContainer.fromBinder(hop.getAdjacentRoot()).asTaskFragment();
         if (!root1.mCreatedByOrganizer || !root2.mCreatedByOrganizer) {
             throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
                     + " organizer root1=" + root1 + " root2=" + root2);
         }
-        root1.setAdjacentTask(root2);
+        root1.setAdjacentTaskFragment(root2);
         return TRANSACT_EFFECTS_LIFECYCLE;
     }
 
@@ -747,6 +794,11 @@
         return mDisplayAreaOrganizerController;
     }
 
+    @Override
+    public ITaskFragmentOrganizerController getTaskFragmentOrganizerController() {
+        return mTaskFragmentOrganizerController;
+    }
+
     @VisibleForTesting
     int startSyncWithOrganizer(IWindowContainerTransactionCallback callback) {
         int id = mService.mWindowManager.mSyncEngine.startSyncSet(this);
@@ -795,6 +847,22 @@
         }
     }
 
+    /** Whether the configuration changes are important to report back to an organizer. */
+    static boolean configurationsAreEqualForOrganizer(
+            Configuration newConfig, @Nullable Configuration oldConfig) {
+        if (oldConfig == null) {
+            return false;
+        }
+        int cfgChanges = newConfig.diff(oldConfig);
+        final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
+                ? (int) newConfig.windowConfiguration.diff(oldConfig.windowConfiguration,
+                true /* compareUndefined */) : 0;
+        if ((winCfgChanges & CONTROLLABLE_WINDOW_CONFIGS) == 0) {
+            cfgChanges &= ~ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+        }
+        return (cfgChanges & CONTROLLABLE_CONFIGS) == 0;
+    }
+
     private void enforceTaskPermission(String func) {
         mService.enforceTaskPermission(func);
     }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 26cfbdf..bee722e 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -25,6 +25,13 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.wm.ActivityRecord.State.DESTROYED;
+import static com.android.server.wm.ActivityRecord.State.DESTROYING;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STARTED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
@@ -32,13 +39,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.Task.ActivityState.DESTROYED;
-import static com.android.server.wm.Task.ActivityState.DESTROYING;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.ActivityState.STARTED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -735,10 +735,10 @@
         if (canUpdate) {
             // Make sure the previous top activity in the process no longer be resumed.
             if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)) {
-                final Task task = mPreQTopResumedActivity.getTask();
-                if (task != null) {
-                    boolean userLeaving = task.shouldBeVisible(null);
-                    task.startPausingLocked(userLeaving, false /* uiSleeping */,
+                final TaskFragment taskFrag = mPreQTopResumedActivity.getTaskFragment();
+                if (taskFrag != null) {
+                    boolean userLeaving = taskFrag.shouldBeVisible(null);
+                    taskFrag.startPausing(userLeaving, false /* uiSleeping */,
                             activity, "top-resumed-changed");
                 }
             }
@@ -989,7 +989,7 @@
         // Since there could be more than one activities in a process record, we don't need to
         // compute the OomAdj with each of them, just need to find out the activity with the
         // "best" state, the order would be visible, pausing, stopping...
-        Task.ActivityState bestInvisibleState = DESTROYED;
+        ActivityRecord.State bestInvisibleState = DESTROYED;
         boolean allStoppingFinishing = true;
         boolean visible = false;
         int minTaskLayer = Integer.MAX_VALUE;
@@ -1213,12 +1213,12 @@
                 hasVisibleActivities = true;
             }
 
-            final Task task = r.getTask();
-            if (task != null) {
+            final TaskFragment taskFragment = r.getTaskFragment();
+            if (taskFragment != null) {
                 // There may be a pausing activity that hasn't shown any window and was requested
                 // to be hidden. But pausing is also a visible state, it should be regarded as
                 // visible, so the caller can know the next activity should be resumed.
-                hasVisibleActivities |= task.handleAppDied(this);
+                hasVisibleActivities |= taskFragment.handleAppDied(this);
             }
             r.handleAppDied();
         }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c3fc995..8ec6ed2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -34,6 +34,7 @@
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.SurfaceControl.Transaction;
 import static android.view.SurfaceControl.getGlobalTransaction;
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -202,6 +203,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.gui.TouchOcclusionMode;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Debug;
@@ -211,7 +213,6 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.TouchOcclusionMode;
 import android.os.Trace;
 import android.os.WorkSource;
 import android.provider.Settings;
@@ -1259,8 +1260,8 @@
         frame.inset(left, top, right, bottom);
     }
 
-    void computeFrameAndUpdateSourceFrame() {
-        computeFrame();
+    void computeFrameAndUpdateSourceFrame(DisplayFrames displayFrames) {
+        computeFrame(displayFrames);
         // Update the source frame to provide insets to other windows during layout. If the
         // simulated frames exist, then this is not computing a stable result so just skip.
         if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) {
@@ -1271,7 +1272,7 @@
     /**
      * Perform standard frame computation. The result can be obtained with getFrame() if so desired.
      */
-    void computeFrame() {
+    void computeFrame(DisplayFrames displayFrames) {
         if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
@@ -1384,7 +1385,8 @@
         final int fw = windowFrames.mFrame.width();
         final int fh = windowFrames.mFrame.height();
 
-        applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame);
+        applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame,
+                displayFrames);
 
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
             if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
@@ -1477,6 +1479,18 @@
         return mAttrs;
     }
 
+    WindowManager.LayoutParams getLayoutingAttrs(int rotation) {
+        if (!INSETS_LAYOUT_GENERALIZATION) {
+            return mAttrs;
+        }
+        final WindowManager.LayoutParams[] paramsForRotation = mAttrs.paramsForRotation;
+        if (paramsForRotation == null || paramsForRotation.length != 4
+                || paramsForRotation[rotation] == null) {
+            return mAttrs;
+        }
+        return paramsForRotation[rotation];
+    }
+
     /** Retrieves the flags used to disable system UI functions. */
     int getDisableFlags() {
         return mDisableFlags;
@@ -1842,9 +1856,8 @@
         return super.hasContentToDisplay();
     }
 
-    @Override
-    boolean isVisible() {
-        return wouldBeVisibleIfPolicyIgnored() && isVisibleByPolicy()
+    private boolean isVisibleByPolicyOrInsets() {
+        return isVisibleByPolicy()
                 // If we don't have a provider, this window isn't used as a window generating
                 // insets, so nobody can hide it over the inset APIs.
                 && (mControllableInsetProvider == null
@@ -1852,11 +1865,18 @@
     }
 
     @Override
+    boolean isVisible() {
+        return wouldBeVisibleIfPolicyIgnored() && isVisibleByPolicyOrInsets();
+    }
+
+    @Override
     boolean isVisibleRequested() {
-        if (shouldCheckTokenVisibleRequested()) {
-            return isVisible() && mToken.isVisibleRequested();
+        final boolean localVisibleRequested =
+                wouldBeVisibleRequestedIfPolicyIgnored() && isVisibleByPolicyOrInsets();
+        if (localVisibleRequested && shouldCheckTokenVisibleRequested()) {
+            return mToken.isVisibleRequested();
         }
-        return isVisible();
+        return localVisibleRequested;
     }
 
     /**
@@ -1903,6 +1923,16 @@
         return !isWallpaper || mToken.isVisible();
     }
 
+    private boolean wouldBeVisibleRequestedIfPolicyIgnored() {
+        final WindowState parent = getParentWindow();
+        final boolean isParentHiddenRequested = parent != null && !parent.isVisibleRequested();
+        if (isParentHiddenRequested || mAnimatingExit || mDestroying) {
+            return false;
+        }
+        final boolean isWallpaper = mToken.asWallpaperToken() != null;
+        return !isWallpaper || mToken.isVisibleRequested();
+    }
+
     /**
      * Is this window visible, ignoring its app token? It is not visible if there is no surface,
      * or we are in the process of running an exit animation that will remove the surface.
@@ -3863,7 +3893,7 @@
         final boolean forceRelayout = syncRedraw || reportOrientation || isDragResizeChanged();
         final DisplayContent displayContent = getDisplayContent();
         final boolean alwaysConsumeSystemBars =
-                displayContent.getDisplayPolicy().areSystemBarsForcedShownLw(this);
+                displayContent.getDisplayPolicy().areSystemBarsForcedShownLw();
         final int displayId = displayContent.getDisplayId();
 
         markRedrawForSyncReported();
@@ -4397,12 +4427,13 @@
     }
 
     private void applyGravityAndUpdateFrame(WindowFrames windowFrames, Rect containingFrame,
-            Rect displayFrame) {
+            Rect displayFrame, DisplayFrames displayFrames) {
         final int pw = containingFrame.width();
         final int ph = containingFrame.height();
         final Task task = getTask();
         final boolean inNonFullscreenContainer = !inAppWindowThatMatchesParentBounds();
-        final boolean noLimits = (mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
+        final WindowManager.LayoutParams attrs = getLayoutingAttrs(displayFrames.mRotation);
+        final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
 
         // We need to fit it to the display if either
         // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen
@@ -4412,49 +4443,54 @@
         // screen, but SurfaceViews want to be always at a specific location so we don't fit it to
         // the display.
         final boolean fitToDisplay = (task == null || !inNonFullscreenContainer)
-                || ((mAttrs.type != TYPE_BASE_APPLICATION) && !noLimits);
+                || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);
         float x, y;
         int w,h;
 
         final boolean hasCompatScale = hasCompatScale();
-        if ((mAttrs.flags & FLAG_SCALED) != 0) {
-            if (mAttrs.width < 0) {
+        if ((attrs.flags & FLAG_SCALED) != 0 || mAttrs != attrs) {
+            // For the window with different layout attrs for different rotations, we need to avoid
+            // using requested size. Otherwise, when finishing a simulated rotation, the information
+            // coming from WindowManagerServices to the ViewRootImpl may not contain the correct
+            // value for the new rotation, and there will be a quick flash of wrong layout when the
+            // simulated activity faded out.
+            if (attrs.width < 0) {
                 w = pw;
             } else if (hasCompatScale) {
-                w = (int)(mAttrs.width * mGlobalScale + .5f);
+                w = (int) (attrs.width * mGlobalScale + .5f);
             } else {
-                w = mAttrs.width;
+                w = attrs.width;
             }
-            if (mAttrs.height < 0) {
+            if (attrs.height < 0) {
                 h = ph;
             } else if (hasCompatScale) {
-                h = (int)(mAttrs.height * mGlobalScale + .5f);
+                h = (int) (attrs.height * mGlobalScale + .5f);
             } else {
-                h = mAttrs.height;
+                h = attrs.height;
             }
         } else {
-            if (mAttrs.width == MATCH_PARENT) {
+            if (attrs.width == MATCH_PARENT) {
                 w = pw;
             } else if (hasCompatScale) {
-                w = (int)(mRequestedWidth * mGlobalScale + .5f);
+                w = (int) (mRequestedWidth * mGlobalScale + .5f);
             } else {
                 w = mRequestedWidth;
             }
-            if (mAttrs.height == MATCH_PARENT) {
+            if (attrs.height == MATCH_PARENT) {
                 h = ph;
             } else if (hasCompatScale) {
-                h = (int)(mRequestedHeight * mGlobalScale + .5f);
+                h = (int) (mRequestedHeight * mGlobalScale + .5f);
             } else {
                 h = mRequestedHeight;
             }
         }
 
         if (hasCompatScale) {
-            x = mAttrs.x * mGlobalScale;
-            y = mAttrs.y * mGlobalScale;
+            x = attrs.x * mGlobalScale;
+            y = attrs.y * mGlobalScale;
         } else {
-            x = mAttrs.x;
-            y = mAttrs.y;
+            x = attrs.x;
+            y = attrs.y;
         }
 
         if (inNonFullscreenContainer && !layoutInParentFrame()) {
@@ -4481,13 +4517,12 @@
         }
 
         // Set mFrame
-        Gravity.apply(mAttrs.gravity, w, h, containingFrame,
-                (int) (x + mAttrs.horizontalMargin * pw),
-                (int) (y + mAttrs.verticalMargin * ph), windowFrames.mFrame);
-
+        Gravity.apply(attrs.gravity, w, h, containingFrame,
+                (int) (x + attrs.horizontalMargin * pw),
+                (int) (y + attrs.verticalMargin * ph), windowFrames.mFrame);
         // Now make sure the window fits in the overall display frame.
         if (fitToDisplay) {
-            Gravity.applyDisplay(mAttrs.gravity, displayFrame, windowFrames.mFrame);
+            Gravity.applyDisplay(attrs.gravity, displayFrame, windowFrames.mFrame);
         }
 
         // We need to make sure we update the CompatFrame as it is used for
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index fbfa400..2624142 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,9 +16,11 @@
 
 package com.android.server.wm;
 
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -451,9 +453,24 @@
     }
 
     Rect getFixedRotationBarContentFrame(int windowType) {
-        return isFixedRotationTransforming()
-                ? mFixedRotationTransformState.mBarContentFrames.get(windowType)
-                : null;
+        if (!isFixedRotationTransforming()) {
+            return null;
+        }
+        if (!INSETS_LAYOUT_GENERALIZATION) {
+            return mFixedRotationTransformState.mBarContentFrames.get(windowType);
+        }
+        final DisplayFrames displayFrames = mFixedRotationTransformState.mDisplayFrames;
+        final Rect tmpRect = new Rect();
+        if (windowType == TYPE_NAVIGATION_BAR) {
+            tmpRect.set(displayFrames.mInsetsState.getSource(InsetsState.ITYPE_NAVIGATION_BAR)
+                    .getFrame());
+        }
+        if (windowType == TYPE_STATUS_BAR) {
+            tmpRect.set(displayFrames.mInsetsState.getSource(InsetsState.ITYPE_STATUS_BAR)
+                    .getFrame());
+        }
+        tmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+        return tmpRect;
     }
 
     InsetsState getFixedRotationTransformInsetsState() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index c29de90..939a3dc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -389,9 +389,15 @@
             mCriticalLevelLogged = false;
             Slog.i(TAG, "Pending logs buffer full. Discarding old logs.");
         }
-        if (DEBUG) Slog.d(TAG, mPendingLogs.size() + " pending events in the buffer after merging,"
-                + " with ids " + mPendingLogs.get(0).getId()
-                + " to " + mPendingLogs.get(mPendingLogs.size() - 1).getId());
+        if (DEBUG) {
+            if (mPendingLogs.size() > 0) {
+                Slog.d(TAG, mPendingLogs.size() + " pending events in the buffer after merging,"
+                        + " with ids " + mPendingLogs.get(0).getId()
+                        + " to " + mPendingLogs.get(mPendingLogs.size() - 1).getId());
+            } else {
+                Slog.d(TAG, "0 pending events in the buffer after merging");
+            }
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d487483..ad89e96 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -103,6 +103,7 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
+import com.android.server.art.ArtManagerLocal;
 import com.android.server.attention.AttentionManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.AuthService;
@@ -2631,6 +2632,10 @@
         mSystemServiceManager.startService(GAME_MANAGER_SERVICE_CLASS);
         t.traceEnd();
 
+        t.traceBegin("ArtManagerLocal");
+        LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
+        t.traceEnd();
+
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
             t.traceBegin("UwbService");
             mSystemServiceManager.startService(UWB_SERVICE_CLASS);
diff --git a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
index aca48b6..ee5a534 100644
--- a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
@@ -19,8 +19,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.os.Build;
 import android.os.Environment;
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
index 6f168a3..7b821c0 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidTest.xml
@@ -32,6 +32,7 @@
     <!-- Load additional APKs onto device -->
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="push" value="AppEnumerationSyncProviderTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationSyncProviderTestApp.apk" />
+        <option name="push" value="AppEnumerationHasAppOpPermissionTestApp.apk->/data/local/tmp/appenumerationtests/AppEnumerationHasAppOpPermissionTestApp.apk" />
     </target_preparer>
 
     <option name="test-tag" value="AppEnumerationInternalTest" />
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index 9337845..63aaf24 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -43,8 +43,16 @@
     private static final String TEST_DATA_PATH = "/data/local/tmp/appenumerationtests/";
     private static final String SYNC_PROVIDER_APK_PATH =
             TEST_DATA_PATH + "AppEnumerationSyncProviderTestApp.apk";
-    private static final String SYNC_PROVIDER_PKG_NAME = "com.android.appenumeration.syncprovider";
-    private static final String SYNC_PROVIDER_AUTHORITY = SYNC_PROVIDER_PKG_NAME;
+    private static final String HAS_APPOP_PERMISSION_APK_PATH =
+            TEST_DATA_PATH + "AppEnumerationHasAppOpPermissionTestApp.apk";
+
+    private static final String TARGET_SYNC_PROVIDER = "com.android.appenumeration.syncprovider";
+    private static final String TARGET_HAS_APPOP_PERMISSION =
+            "com.android.appenumeration.hasappoppermission";
+
+    private static final String SYNC_PROVIDER_AUTHORITY = TARGET_SYNC_PROVIDER;
+    private static final String PERMISSION_REQUEST_INSTALL_PACKAGES =
+            "android.permission.REQUEST_INSTALL_PACKAGES";
 
     private IPackageManager mIPackageManager;
 
@@ -55,7 +63,8 @@
 
     @After
     public void tearDown() throws Exception {
-        uninstallPackage(SYNC_PROVIDER_PKG_NAME);
+        uninstallPackage(TARGET_SYNC_PROVIDER);
+        uninstallPackage(TARGET_HAS_APPOP_PERMISSION);
     }
 
     @Test
@@ -67,7 +76,7 @@
 
         assertThat(names).contains(SYNC_PROVIDER_AUTHORITY);
         assertThat(infos.stream().map(info -> info.packageName).collect(Collectors.toList()))
-                .contains(SYNC_PROVIDER_PKG_NAME);
+                .contains(TARGET_SYNC_PROVIDER);
     }
 
     @Test
@@ -79,7 +88,27 @@
 
         assertThat(names).doesNotContain(SYNC_PROVIDER_AUTHORITY);
         assertThat(infos.stream().map(info -> info.packageName).collect(Collectors.toList()))
-                .doesNotContain(SYNC_PROVIDER_PKG_NAME);
+                .doesNotContain(TARGET_SYNC_PROVIDER);
+    }
+
+    @Test
+    public void getAppOpPermissionPackages_canSeeForceQueryable() throws Exception {
+        installPackage(HAS_APPOP_PERMISSION_APK_PATH, true /* forceQueryable */);
+
+        final String[] packageNames = mIPackageManager.getAppOpPermissionPackages(
+                PERMISSION_REQUEST_INSTALL_PACKAGES);
+
+        assertThat(packageNames).asList().contains(TARGET_HAS_APPOP_PERMISSION);
+    }
+
+    @Test
+    public void getAppOpPermissionPackages_cannotSeeHasAppOpPermission() throws Exception {
+        installPackage(HAS_APPOP_PERMISSION_APK_PATH, false /* forceQueryable */);
+
+        final String[] packageNames = mIPackageManager.getAppOpPermissionPackages(
+                PERMISSION_REQUEST_INSTALL_PACKAGES);
+
+        assertThat(packageNames).asList().doesNotContain(TARGET_HAS_APPOP_PERMISSION);
     }
 
     private static void installPackage(String apkPath, boolean forceQueryable) {
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
index 64239b4..7aa300b 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/Android.bp
@@ -34,3 +34,17 @@
     test_suites: ["device-tests"],
     platform_apis: true,
 }
+
+android_test_helper_app {
+    name: "AppEnumerationHasAppOpPermissionTestApp",
+    srcs: ["src/**/*.java"],
+    manifest: "AndroidManifest-hasAppOpPermission.xml",
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    test_suites: ["device-tests"],
+    platform_apis: true,
+}
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-hasAppOpPermission.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-hasAppOpPermission.xml
new file mode 100644
index 0000000..be8a6dc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-hasAppOpPermission.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="com.android.appenumeration.hasappoppermission">
+
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
index 022fadc..15dfd26 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -21,12 +21,15 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 
+import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManagerInternal;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -48,7 +51,10 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.File;
-import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -62,6 +68,8 @@
  */
 @RunWith(MockitoJUnitRunner.class)
 public class CacheOomRankerTest {
+    private static final Instant NOW = LocalDate.of(2021, 1, 1).atStartOfDay(
+            ZoneOffset.UTC).toInstant();
 
     @Mock
     private AppOpsService mAppOpsService;
@@ -136,6 +144,15 @@
 
         mExecutor.init();
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS,
+                Integer.toString(CacheOomRanker.DEFAULT_PRESERVE_TOP_N_APPS + 1),
+                false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.mPreserveTopNApps)
+                .isEqualTo(CacheOomRanker.DEFAULT_PRESERVE_TOP_N_APPS + 1);
+
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
                 Float.toString(CacheOomRanker.DEFAULT_OOM_RE_RANKING_LRU_WEIGHT + 0.1f),
                 false);
@@ -165,6 +182,7 @@
     @Test
     public void reRankLruCachedApps_lruImpactsOrdering() throws InterruptedException {
         setConfig(/* numberToReRank= */ 5,
+                /* preserveTopNApps= */ 0,
                 /* usesWeight= */ 0.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */1.0f);
@@ -172,36 +190,38 @@
         ProcessList list = new ProcessList();
         ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
         ProcessRecord lastUsed40MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
         processList.add(lastUsed40MinutesAgo);
         ProcessRecord lastUsed42MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
         processList.add(lastUsed42MinutesAgo);
         ProcessRecord lastUsed60MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(60).toMillis(), 1024L, 10000);
+                NOW.minus(60, ChronoUnit.MINUTES).toEpochMilli(), 1024L, 10000);
         processList.add(lastUsed60MinutesAgo);
         ProcessRecord lastUsed15MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
         processList.add(lastUsed15MinutesAgo);
         ProcessRecord lastUsed17MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(17).toMillis(), 1024L, 20);
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 1024L, 20);
         processList.add(lastUsed17MinutesAgo);
         // Only re-ranking 5 entries so this should stay in most recent position.
         ProcessRecord lastUsed30MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 1024L, 20);
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 1024L, 20);
         processList.add(lastUsed30MinutesAgo);
+        list.setLruProcessServiceStartLSP(processList.size());
 
         mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
 
         // First 5 ordered by least recently used first, then last processes position unchanged.
         assertThat(processList).containsExactly(lastUsed60MinutesAgo, lastUsed42MinutesAgo,
                 lastUsed40MinutesAgo, lastUsed17MinutesAgo, lastUsed15MinutesAgo,
-                lastUsed30MinutesAgo);
+                lastUsed30MinutesAgo).inOrder();
     }
 
     @Test
     public void reRankLruCachedApps_rssImpactsOrdering() throws InterruptedException {
         setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ 0,
                 /* usesWeight= */ 0.0f,
                 /* pssWeight= */ 1.0f,
                 /* lruWeight= */ 0.0f);
@@ -209,145 +229,328 @@
         ProcessList list = new ProcessList();
         ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
         ProcessRecord rss10k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
         processList.add(rss10k);
         ProcessRecord rss20k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
         processList.add(rss20k);
         ProcessRecord rss1k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(60).toMillis(), 1024L, 10000);
+                NOW.minus(60, ChronoUnit.MINUTES).toEpochMilli(), 1024L, 10000);
         processList.add(rss1k);
         ProcessRecord rss100k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
         processList.add(rss100k);
         ProcessRecord rss2k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
         processList.add(rss2k);
         ProcessRecord rss15k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 20);
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 20);
         processList.add(rss15k);
         // Only re-ranking 6 entries so this should stay in most recent position.
         ProcessRecord rss16k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 20);
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 20);
         processList.add(rss16k);
+        list.setLruProcessServiceStartLSP(processList.size());
 
         mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
 
         // First 6 ordered by largest pss, then last processes position unchanged.
         assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k,
-                rss16k);
+                rss16k).inOrder();
     }
 
     @Test
     public void reRankLruCachedApps_usesImpactsOrdering() throws InterruptedException {
         setConfig(/* numberToReRank= */ 4,
+                /* preserveTopNApps= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
 
         ProcessList list = new ProcessList();
-        list.setLruProcessServiceStartLSP(1);
         ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
         ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
         processList.add(used1000);
         ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
         processList.add(used2000);
         ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
         processList.add(used10);
         ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
         processList.add(used20);
         // Only re-ranking 6 entries so last two should stay in most recent position.
         ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 500);
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
         processList.add(used500);
         ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200);
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
         processList.add(used200);
+        list.setLruProcessServiceStartLSP(processList.size());
 
         mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
 
         // First 4 ordered by uses, then last processes position unchanged.
         assertThat(processList).containsExactly(used10, used20, used1000, used2000, used500,
-                used200);
+                used200).inOrder();
     }
 
     @Test
-    public void reRankLruCachedApps_notEnoughProcesses() throws InterruptedException {
+    public void reRankLruCachedApps_fewProcesses() throws InterruptedException {
         setConfig(/* numberToReRank= */ 4,
-                /* usesWeight= */ 0.5f,
-                /* pssWeight= */ 0.2f,
-                /* lruWeight= */ 0.3f);
-
-        ProcessList list = new ProcessList();
-        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
-        ProcessRecord unknownAdj1 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
-        processList.add(unknownAdj1);
-        ProcessRecord unknownAdj2 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
-        processList.add(unknownAdj2);
-        ProcessRecord unknownAdj3 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
-        processList.add(unknownAdj3);
-        ProcessRecord foregroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
-                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
-        processList.add(foregroundAdj);
-        ProcessRecord serviceAdj = nextProcessRecord(ProcessList.SERVICE_ADJ,
-                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 500);
-        processList.add(serviceAdj);
-        ProcessRecord systemAdj = nextProcessRecord(ProcessList.SYSTEM_ADJ,
-                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200);
-        processList.add(systemAdj);
-
-        // 6 Processes but only 3 in eligible for cache so no re-ranking.
-        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
-
-        // All positions unchanged.
-        assertThat(processList).containsExactly(unknownAdj1, unknownAdj2, unknownAdj3,
-                foregroundAdj, serviceAdj, systemAdj);
-    }
-
-    @Test
-    public void reRankLruCachedApps_notEnoughNonServiceProcesses() throws InterruptedException {
-        setConfig(/* numberToReRank= */ 4,
+                /* preserveTopNApps= */ 0,
                 /* usesWeight= */ 1.0f,
                 /* pssWeight= */ 0.0f,
                 /* lruWeight= */ 0.0f);
 
         ProcessList list = new ProcessList();
-        list.setLruProcessServiceStartLSP(4);
         ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
         ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
         processList.add(used1000);
         ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
         processList.add(used2000);
         ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
         processList.add(used10);
-        ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
-        processList.add(used20);
-        ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 500);
-        processList.add(used500);
-        ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
-                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200);
-        processList.add(used200);
+        ProcessRecord foregroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        processList.add(foregroundAdj);
+        ProcessRecord serviceAdj = nextProcessRecord(ProcessList.SERVICE_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        processList.add(serviceAdj);
+        ProcessRecord systemAdj = nextProcessRecord(ProcessList.SYSTEM_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        processList.add(systemAdj);
+        list.setLruProcessServiceStartLSP(processList.size());
 
         mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
 
-        // All positions unchanged.
-        assertThat(processList).containsExactly(used1000, used2000, used10, used20, used500,
-                used200);
+        // 6 processes, only 3 in eligible for cache, so only those are re-ranked.
+        assertThat(processList).containsExactly(used10, used1000, used2000,
+                foregroundAdj, serviceAdj, systemAdj).inOrder();
     }
 
-    private void setConfig(int numberToReRank, float useWeight, float pssWeight, float lruWeight)
+    @Test
+    public void reRankLruCachedApps_fewNonServiceProcesses() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 4,
+                /* preserveTopNApps= */ 0,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
+        ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        processList.add(used1000);
+        ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        processList.add(used2000);
+        ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        processList.add(used10);
+        ProcessRecord service1 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        processList.add(service1);
+        ProcessRecord service2 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        processList.add(service2);
+        ProcessRecord service3 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        processList.add(service3);
+        list.setLruProcessServiceStartLSP(3);
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+
+        // Services unchanged, rest re-ranked.
+        assertThat(processList).containsExactly(used10, used1000, used2000, service1, service2,
+                service3).inOrder();
+    }
+
+    @Test
+    public void reRankLruCachedApps_manyProcessesThenFew() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ 0,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList set1List = new ProcessList();
+        ArrayList<ProcessRecord> set1ProcessList = set1List.getLruProcessesLSP();
+        ProcessRecord set1Used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        set1ProcessList.add(set1Used1000);
+        ProcessRecord set1Used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        set1ProcessList.add(set1Used2000);
+        ProcessRecord set1Used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        set1ProcessList.add(set1Used10);
+        ProcessRecord set1Uses20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        set1ProcessList.add(set1Uses20);
+        ProcessRecord set1Uses500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        set1ProcessList.add(set1Uses500);
+        ProcessRecord set1Uses200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        set1ProcessList.add(set1Uses200);
+        set1List.setLruProcessServiceStartLSP(set1ProcessList.size());
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(set1ProcessList,
+                set1List.getLruProcessServiceStartLOSP());
+        assertThat(set1ProcessList).containsExactly(set1Used10, set1Uses20, set1Uses200,
+                set1Uses500, set1Used1000, set1Used2000).inOrder();
+
+        ProcessList set2List = new ProcessList();
+        ArrayList<ProcessRecord> set2ProcessList = set2List.getLruProcessesLSP();
+        ProcessRecord set2Used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        set2ProcessList.add(set2Used1000);
+        ProcessRecord set2Used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        set2ProcessList.add(set2Used2000);
+        ProcessRecord set2Used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        set2ProcessList.add(set2Used10);
+        ProcessRecord set2ForegroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        set2ProcessList.add(set2ForegroundAdj);
+        ProcessRecord set2ServiceAdj = nextProcessRecord(ProcessList.SERVICE_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        set2ProcessList.add(set2ServiceAdj);
+        ProcessRecord set2SystemAdj = nextProcessRecord(ProcessList.SYSTEM_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        set2ProcessList.add(set2SystemAdj);
+        set2List.setLruProcessServiceStartLSP(set2ProcessList.size());
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(set2ProcessList,
+                set2List.getLruProcessServiceStartLOSP());
+        assertThat(set2ProcessList).containsExactly(set2Used10, set2Used1000, set2Used2000,
+                set2ForegroundAdj, set2ServiceAdj, set2SystemAdj).inOrder();
+    }
+
+    @Test
+    public void reRankLruCachedApps_preservesTopNApps() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ 3,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
+        ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        processList.add(used1000);
+        ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        processList.add(used2000);
+        ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        processList.add(used10);
+        // Preserving the top 3 processes, so these should not be re-ranked.
+        ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        processList.add(used20);
+        ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        processList.add(used500);
+        ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        processList.add(used200);
+        list.setLruProcessServiceStartLSP(processList.size());
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+
+        // First 3 ordered by uses, then last processes position unchanged.
+        assertThat(processList).containsExactly(used10, used1000, used2000, used20, used500,
+                used200).inOrder();
+    }
+
+    @Test
+    public void reRankLruCachedApps_preservesTopNApps_allAppsUnchanged()
+            throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ 100,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
+        ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        processList.add(used1000);
+        ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        processList.add(used2000);
+        ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        processList.add(used10);
+        ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        processList.add(used20);
+        ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        processList.add(used500);
+        ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        processList.add(used200);
+        list.setLruProcessServiceStartLSP(processList.size());
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+
+        // Nothing reordered, as we preserve the top 100 apps.
+        assertThat(processList).containsExactly(used1000, used2000, used10, used20, used500,
+                used200).inOrder();
+    }
+
+    @Test
+    public void reRankLruCachedApps_preservesTopNApps_negativeReplacedWithDefault()
+            throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* preserveTopNApps= */ -100,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.getLruProcessesLSP();
+        ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(40, ChronoUnit.MINUTES).toEpochMilli(), 10 * 1024L, 1000);
+        processList.add(used1000);
+        ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(42, ChronoUnit.MINUTES).toEpochMilli(), 20 * 1024L, 2000);
+        processList.add(used2000);
+        ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(15, ChronoUnit.MINUTES).toEpochMilli(), 100 * 1024L, 10);
+        processList.add(used10);
+        // Negative preserveTopNApps interpreted as the default (3), so the last three are unranked.
+        ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(17, ChronoUnit.MINUTES).toEpochMilli(), 2 * 1024L, 20);
+        processList.add(used20);
+        ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 15 * 1024L, 500);
+        processList.add(used500);
+        ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                NOW.minus(30, ChronoUnit.MINUTES).toEpochMilli(), 16 * 1024L, 200);
+        processList.add(used200);
+        list.setLruProcessServiceStartLSP(processList.size());
+
+        mCacheOomRanker.reRankLruCachedAppsLSP(processList, list.getLruProcessServiceStartLOSP());
+
+        // First 3 apps re-ranked, as preserveTopNApps is interpreted as 3.
+        assertThat(processList).containsExactly(used10, used1000, used2000, used20, used500,
+                used200).inOrder();
+    }
+
+    private void setConfig(int numberToReRank, int preserveTopNApps, float usesWeight,
+            float pssWeight, float lruWeight)
             throws InterruptedException {
         mExecutor.init(4);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -355,6 +558,10 @@
                 Integer.toString(numberToReRank),
                 false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_PRESERVE_TOP_N_APPS,
+                Integer.toString(preserveTopNApps),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
                 Float.toString(lruWeight),
                 false);
@@ -364,12 +571,12 @@
                 false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CacheOomRanker.KEY_OOM_RE_RANKING_USES_WEIGHT,
-                Float.toString(useWeight),
+                Float.toString(usesWeight),
                 false);
         mExecutor.waitForLatch();
         assertThat(mCacheOomRanker.getNumberToReRank()).isEqualTo(numberToReRank);
         assertThat(mCacheOomRanker.mRssWeight).isEqualTo(pssWeight);
-        assertThat(mCacheOomRanker.mUsesWeight).isEqualTo(useWeight);
+        assertThat(mCacheOomRanker.mUsesWeight).isEqualTo(usesWeight);
         assertThat(mCacheOomRanker.mLruWeight).isEqualTo(lruWeight);
     }
 
@@ -382,7 +589,7 @@
         app.info.uid = mNextPackageUid++;
         // Exact value does not mater, it can be any state for which compaction is allowed.
         app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
-        app.mState.setSetAdj(setAdj);
+        app.mState.setCurAdj(setAdj);
         app.setLastActivityTime(lastActivityTime);
         app.mProfile.setLastRss(lastRss);
         app.mState.setCached(false);
@@ -390,6 +597,12 @@
             app.mState.setCached(false);
             app.mState.setCached(true);
         }
+        // Sets the thread returned by ProcessRecord#getThread, which we use to check whether the
+        // app is currently launching.
+        ProcessStatsService processStatsService = new ProcessStatsService(
+                mock(ActivityManagerService.class), new File(Environment.getDataSystemCeDirectory(),
+                "procstats"));
+        app.makeActive(mock(IApplicationThread.class), processStatsService);
         return app;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index b2471fa..e0cee4b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -97,11 +97,6 @@
             super(context);
             mAppStateTracker = mock(AppStateTrackerImpl.class);
         }
-
-        @Override
-        public boolean isChainedAttributionEnabled() {
-            return false;
-        }
     }
 
     @Before
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 3dc7bc1..c407429 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -299,8 +299,17 @@
         final JobStatus earlyPrefetch = createJobStatus(job, now - 1000, now + 2000);
         final JobStatus latePrefetch = createJobStatus(job, now - 2000, now + 1000);
 
+        job.setEstimatedNetworkBytes(JobInfo.NETWORK_BYTES_UNKNOWN, DataUnit.MEBIBYTES.toBytes(1));
+        final JobStatus latePrefetchUnknownDown = createJobStatus(job, now - 2000, now + 1000);
+        job.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), JobInfo.NETWORK_BYTES_UNKNOWN);
+        final JobStatus latePrefetchUnknownUp = createJobStatus(job, now - 2000, now + 1000);
+
         final ConnectivityController controller = new ConnectivityController(mService);
 
+        when(mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota(
+                any(), eq(NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS)))
+                .thenReturn(0L);
+
         // Unmetered network is whenever
         {
             final Network net = mock(Network.class);
@@ -312,9 +321,11 @@
             assertTrue(controller.isSatisfied(late, net, caps, mConstants));
             assertTrue(controller.isSatisfied(earlyPrefetch, net, caps, mConstants));
             assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants));
+            assertTrue(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
+            assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
         }
 
-        // Metered network is only when prefetching and late
+        // Metered network is only when prefetching, late, and in opportunistic quota
         {
             final Network net = mock(Network.class);
             final NetworkCapabilities caps = createCapabilitiesBuilder()
@@ -323,7 +334,17 @@
             assertFalse(controller.isSatisfied(early, net, caps, mConstants));
             assertFalse(controller.isSatisfied(late, net, caps, mConstants));
             assertFalse(controller.isSatisfied(earlyPrefetch, net, caps, mConstants));
+            assertFalse(controller.isSatisfied(latePrefetch, net, caps, mConstants));
+            assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
+            assertFalse(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
+
+            when(mNetPolicyManagerInternal.getSubscriptionOpportunisticQuota(
+                    any(), eq(NetworkPolicyManagerInternal.QUOTA_TYPE_JOBS)))
+                    .thenReturn(9876543210L);
             assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants));
+            // Only relax restrictions when we at least know the estimated download bytes.
+            assertFalse(controller.isSatisfied(latePrefetchUnknownDown, net, caps, mConstants));
+            assertTrue(controller.isSatisfied(latePrefetchUnknownUp, net, caps, mConstants));
         }
     }
 
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 db0c3ae..d4f17f3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -21,10 +21,10 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.FallbackCategoryProvider
 import android.content.pm.FeatureInfo
-import android.content.pm.PackageParser.SigningDetails
 import android.content.pm.ResolveInfo
 import android.content.pm.ServiceInfo
 import android.content.pm.Signature
+import android.content.pm.SigningDetails
 import android.content.pm.UserInfo
 import android.content.pm.parsing.ParsingPackage
 import android.content.pm.parsing.ParsingPackageUtils
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 68570ff..1ead53f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -227,8 +227,8 @@
         assertThat(destroyedNonReadySession.isDestroyed()).isTrue();
 
         mStagingManager.onBootCompletedBroadcastReceived();
-        assertThat(nonReadyApkSession.hasPreRebootVerificationStarted()).isTrue();
-        assertThat(nonReadyApexSession.hasPreRebootVerificationStarted()).isTrue();
+        assertThat(nonReadyApkSession.hasVerificationStarted()).isTrue();
+        assertThat(nonReadyApexSession.hasVerificationStarted()).isTrue();
     }
 
     @Test
@@ -521,7 +521,7 @@
         private int mParentSessionId = -1;
         private String mPackageName;
         private boolean mIsAbandonded = false;
-        private boolean mPreRebootVerificationStarted = false;
+        private boolean mVerificationStarted = false;
         private final List<StagingManager.StagedSession> mChildSessions = new ArrayList<>();
 
         private FakeStagedSession(int sessionId) {
@@ -552,8 +552,8 @@
             return mIsAbandonded;
         }
 
-        private boolean hasPreRebootVerificationStarted() {
-            return mPreRebootVerificationStarted;
+        private boolean hasVerificationStarted() {
+            return mVerificationStarted;
         }
 
         private FakeStagedSession addChildSession(FakeStagedSession session) {
@@ -708,20 +708,13 @@
         }
 
         @Override
-        public boolean notifyStartPreRebootVerification() {
-            mPreRebootVerificationStarted = true;
-            // TODO(ioffe): change to true when tests for pre-reboot verification are added.
-            return false;
-        }
-
-        @Override
         public void notifyEndPreRebootVerification() {
             throw new UnsupportedOperationException();
         }
 
         @Override
         public void verifySession() {
-            throw new UnsupportedOperationException();
+            mVerificationStarted = true;
         }
     }
 }
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 339a5f9..4abc7ee 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -117,6 +117,7 @@
         ":PackageParserTestApp2",
         ":PackageParserTestApp3",
         ":PackageParserTestApp4",
+        ":PackageParserTestApp5",
         ":apex.test",
         ":test.rebootless_apex_v1",
         ":test.rebootless_apex_v2",
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index d6c11a5..e612d12 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -65,6 +65,7 @@
 import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index ee00cb2..c5416fb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -595,7 +595,7 @@
         serviceInfo.permission = android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE;
         mA11ySecurityPolicy.canRegisterService(serviceInfo);
         verify(mMockAppOpsManager).noteOpNoThrow(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE,
-                serviceInfo.applicationInfo.uid, serviceInfo.packageName);
+                serviceInfo.applicationInfo.uid, serviceInfo.packageName, null, null);
     }
 
     @Test
@@ -617,7 +617,7 @@
 
         mA11ySecurityPolicy.checkAccessibilityAccess(mMockA11yServiceConnection);
         verify(mMockAppOpsManager).noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
-                APP_UID, PACKAGE_NAME);
+                APP_UID, PACKAGE_NAME, null, null);
     }
 
     @Test
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 00daa5c..432a500 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.GestureDescription;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index e4d51e4..4afe099 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -120,6 +120,7 @@
     @Mock private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
     @Mock private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
     @Mock private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
+    @Mock private AccessibilityTraceManager mMockA11yTraceManager;
 
     @Mock private IBinder mMockHostToken;
     @Mock private IBinder mMockEmbeddedToken;
@@ -140,7 +141,8 @@
                 mMockWindowManagerInternal,
                 mMockA11yEventSender,
                 mMockA11ySecurityPolicy,
-                mMockA11yUserManager);
+                mMockA11yUserManager,
+                mMockA11yTraceManager);
         // Starts tracking window of default display and sets the default display
         // as top focused display before each testing starts.
         startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
@@ -834,6 +836,19 @@
         assertNull(token);
     }
 
+    @Test
+    public void onDisplayReparented_shouldRemoveObserver() throws RemoteException {
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
+        // Notifies the second display is an embedded one of the default display.
+        final WindowsForAccessibilityCallback callbacks =
+                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
+        callbacks.onDisplayReparented(SECONDARY_DISPLAY_ID);
+        // Makes sure the observer of the second display is removed.
+        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
+    }
+
     private void registerLeashedTokenAndWindowId() {
         mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
         mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
index 78e651b..c62cae5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
@@ -56,11 +56,13 @@
     private MessageCapturingHandler mHandler = new MessageCapturingHandler(
             msg -> mInterceptor.handleMessage(msg));
     @Mock AccessibilityManagerService mMockAms;
+    @Mock AccessibilityTraceManager mMockTraceManager;
     @Mock WindowManagerPolicy mMockPolicy;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mMockAms.getTraceManager()).thenReturn(mMockTraceManager);
         mInterceptor = new KeyboardInterceptor(mMockAms, mMockPolicy, mHandler);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index a71b481..85ea8b4 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -114,6 +114,7 @@
 
     MotionEventInjector mMotionEventInjector;
     IAccessibilityServiceClient mServiceInterface;
+    AccessibilityTraceManager mTrace;
     List<GestureStep> mLineList = new ArrayList<>();
     List<GestureStep> mClickList = new ArrayList<>();
     List<GestureStep> mContinuedLineList1 = new ArrayList<>();
@@ -140,7 +141,8 @@
                 return mMotionEventInjector.handleMessage(msg);
             }
         });
-        mMotionEventInjector = new MotionEventInjector(mMessageCapturingHandler);
+        mTrace = mock(AccessibilityTraceManager.class);
+        mMotionEventInjector = new MotionEventInjector(mMessageCapturingHandler, mTrace);
         mServiceInterface = mock(IAccessibilityServiceClient.class);
 
         mLineList = createSimpleGestureFromPoints(0, 0, false, LINE_DURATION, LINE_START, LINE_END);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 1603087..4ce9ba0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.app.UiAutomation;
 import android.content.Context;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 7bf0bb8..4a06611f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -36,6 +36,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityGestureEvent;
 import android.accessibilityservice.AccessibilityService;
@@ -53,6 +54,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.EventStreamTransformation;
 import com.android.server.accessibility.utils.GestureLogParser;
 import com.android.server.testutils.OffsettableClock;
@@ -107,6 +109,8 @@
 
     @Mock
     private AccessibilityManagerService mMockAms;
+    @Mock
+    private AccessibilityTraceManager mMockTraceManager;
     @Captor
     private ArgumentCaptor<AccessibilityGestureEvent> mGestureCaptor;
 
@@ -143,9 +147,9 @@
         if (Looper.myLooper() == null) {
             Looper.prepare();
         }
+        when(mMockAms.getTraceManager()).thenReturn(mMockTraceManager);
         mContext = InstrumentationRegistry.getContext();
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        AccessibilityManagerService ams = new AccessibilityManagerService(mContext);
         mCaptor = new EventCaptor();
         mHandler = new TestHandler();
         mTouchExplorer = new TouchExplorer(mContext, mMockAms, null, mHandler);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 502f64a..8d90512 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -52,6 +52,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
@@ -93,6 +94,7 @@
             mock(FullScreenMagnificationController.ControllerContext.class);
     final Context mMockContext = mock(Context.class);
     final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class);
+    final AccessibilityTraceManager mMockTraceManager = mock(AccessibilityTraceManager.class);
     final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class);
     private final MagnificationAnimationCallback mAnimationCallback = mock(
             MagnificationAnimationCallback.class);
@@ -113,9 +115,11 @@
         when(mMockContext.getMainLooper()).thenReturn(looper);
         when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
         when(mMockControllerCtx.getAms()).thenReturn(mMockAms);
+        when(mMockControllerCtx.getTraceManager()).thenReturn(mMockTraceManager);
         when(mMockControllerCtx.getWindowManager()).thenReturn(mMockWindowManager);
         when(mMockControllerCtx.getHandler()).thenReturn(mMessageCapturingHandler);
         when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
+        when(mMockAms.getTraceManager()).thenReturn(mMockTraceManager);
         initMockWindowManager();
 
         mFullScreenMagnificationController = new FullScreenMagnificationController(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index f881f04..b14c353 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -52,6 +52,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.EventStreamTransformation;
 import com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationInfoChangedCallback;
 import com.android.server.testutils.OffsettableClock;
@@ -129,6 +130,10 @@
     MagnificationInfoChangedCallback mMagnificationInfoChangedCallback;
     @Mock
     WindowMagnificationPromptController mWindowMagnificationPromptController;
+    @Mock
+    AccessibilityManagerService mMockAccessibilityManagerService;
+    @Mock
+    AccessibilityTraceManager mMockTraceManager;
 
     private OffsettableClock mClock;
     private FullScreenMagnificationGestureHandler mMgh;
@@ -144,7 +149,9 @@
                 mock(FullScreenMagnificationController.ControllerContext.class);
         final WindowManagerInternal mockWindowManager = mock(WindowManagerInternal.class);
         when(mockController.getContext()).thenReturn(mContext);
-        when(mockController.getAms()).thenReturn(mock(AccessibilityManagerService.class));
+        when(mockController.getAms()).thenReturn(mMockAccessibilityManagerService);
+        when(mMockAccessibilityManagerService.getTraceManager()).thenReturn(mMockTraceManager);
+        when(mockController.getTraceManager()).thenReturn(mMockTraceManager);
         when(mockController.getWindowManager()).thenReturn(mockWindowManager);
         when(mockController.getHandler()).thenReturn(new Handler(mContext.getMainLooper()));
         when(mockController.newValueAnimator()).thenReturn(new ValueAnimator());
@@ -179,7 +186,7 @@
     private FullScreenMagnificationGestureHandler newInstance(boolean detectTripleTap,
             boolean detectShortcutTrigger) {
         FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler(
-                mContext, mFullScreenMagnificationController, mMockCallback,
+                mContext, mFullScreenMagnificationController, mMockTraceManager, mMockCallback,
                 detectTripleTap, detectShortcutTrigger,
                 mWindowMagnificationPromptController, DISPLAY_0);
         mHandler = new TestHandler(h.mDetectingState, mClock) {
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 b7f5f4d..e82adc8 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
@@ -54,6 +54,7 @@
 
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.accessibility.AccessibilityManagerService;
+import com.android.server.accessibility.AccessibilityTraceManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -84,6 +85,8 @@
             Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 
     @Mock
+    private AccessibilityTraceManager mTraceManager;
+    @Mock
     private AccessibilityManagerService mService;
     @Mock
     private MagnificationController.TransitionCallBack mTransitionCallBack;
@@ -112,7 +115,7 @@
                 CURRENT_USER_ID);
         mWindowMagnificationManager = Mockito.spy(
                 new WindowMagnificationManager(mContext, CURRENT_USER_ID,
-                        mock(WindowMagnificationManager.Callback.class)));
+                        mock(WindowMagnificationManager.Callback.class), mTraceManager));
         mMockConnection = new MockWindowMagnificationConnection(true);
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
         mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java
index 514d16a..ef6ed88 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java
@@ -31,6 +31,8 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.accessibility.AccessibilityTraceManager;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,6 +51,8 @@
             Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 
     @Mock
+    AccessibilityTraceManager mTraceManager;
+    @Mock
     MagnificationGestureHandler.Callback mCallback;
 
     @Before
@@ -57,6 +61,7 @@
         mMgh = new TestMagnificationGestureHandler(DISPLAY_0,
                 /* detectTripleTap= */true,
                 /* detectShortcutTrigger= */true,
+                mTraceManager,
                 mCallback);
     }
 
@@ -129,8 +134,9 @@
         boolean mIsInternalMethodCalled = false;
 
         TestMagnificationGestureHandler(int displayId, boolean detectTripleTap,
-                boolean detectShortcutTrigger, @NonNull Callback callback) {
-            super(displayId, detectTripleTap, detectShortcutTrigger, callback);
+                boolean detectShortcutTrigger, @NonNull AccessibilityTraceManager trace,
+                @NonNull Callback callback) {
+            super(displayId, detectTripleTap, detectShortcutTrigger, trace, callback);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
index c88bc3b..1638563 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationConnectionWrapperTest.java
@@ -29,6 +29,8 @@
 import android.view.accessibility.IWindowMagnificationConnectionCallback;
 import android.view.accessibility.MagnificationAnimationCallback;
 
+import com.android.server.accessibility.AccessibilityTraceManager;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -45,6 +47,8 @@
 
     private IWindowMagnificationConnection mConnection;
     @Mock
+    private AccessibilityTraceManager mTrace;
+    @Mock
     private IWindowMagnificationConnectionCallback mCallback;
     @Mock
     private MagnificationAnimationCallback mAnimationCallback;
@@ -57,7 +61,7 @@
         MockitoAnnotations.initMocks(this);
         mMockWindowMagnificationConnection = new MockWindowMagnificationConnection();
         mConnection = mMockWindowMagnificationConnection.getConnection();
-        mConnectionWrapper = new WindowMagnificationConnectionWrapper(mConnection);
+        mConnectionWrapper = new WindowMagnificationConnectionWrapper(mConnection, mTrace);
     }
 
     @Test
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 b9498d6..6a5aae6 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
@@ -35,6 +35,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.EventStreamTransformation;
 import com.android.server.accessibility.utils.TouchEventGenerator;
 
@@ -74,16 +75,18 @@
     private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
     @Mock
     MagnificationGestureHandler.Callback mMockCallback;
+    @Mock
+    AccessibilityTraceManager mMockTrace;
 
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
-                mock(WindowMagnificationManager.Callback.class));
+                mock(WindowMagnificationManager.Callback.class), mMockTrace);
         mMockConnection = new MockWindowMagnificationConnection();
         mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
-                mContext, mWindowMagnificationManager, mMockCallback,
+                mContext, mWindowMagnificationManager, mMockTrace, mMockCallback,
                 /** detectTripleTap= */true,   /** detectShortcutTrigger= */true, DISPLAY_0);
         mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
         mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
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 a20272a..af6d40f 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
@@ -52,6 +52,7 @@
 
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.LocalServices;
+import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import org.junit.Before;
@@ -72,6 +73,8 @@
     @Mock
     private Context mContext;
     @Mock
+    private AccessibilityTraceManager mMockTrace;
+    @Mock
     private StatusBarManagerInternal mMockStatusBarManagerInternal;
     @Mock
     private MagnificationAnimationCallback mAnimationCallback;
@@ -88,7 +91,7 @@
         mResolver = new MockContentResolver();
         mMockConnection = new MockWindowMagnificationConnection();
         mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID,
-                mMockCallback);
+                mMockCallback, mMockTrace);
 
         when(mContext.getContentResolver()).thenReturn(mResolver);
         doAnswer((InvocationOnMock invocation) -> {
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
index 54945fb..c0ba3c7 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
@@ -75,7 +75,7 @@
         for (boolean muted : new boolean[] { true, false}) {
             testAudioSystem.configureIsMicrophoneMuted(!muted);
             mAudioService.setMicrophoneMute(muted, mContext.getOpPackageName(),
-                    UserHandle.getCallingUserId());
+                    UserHandle.getCallingUserId(), null);
             Assert.assertEquals("mic mute reporting wrong value",
                     muted, mAudioService.isMicrophoneMuted());
             // verify the intent for mic mute changed is supposed to be fired
@@ -100,7 +100,7 @@
         for (boolean muted : new boolean[] { true, false}) {
             testAudioSystem.configureIsMicrophoneMuted(!muted);
             mAudioService.setMicrophoneMute(muted, mContext.getOpPackageName(),
-                    UserHandle.getCallingUserId());
+                    UserHandle.getCallingUserId(), null);
             Assert.assertEquals("mic mute reporting wrong value",
                     !muted, mAudioService.isMicrophoneMuted());
             // verify the intent for mic mute changed is supposed to be fired
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
index 7323096..7aea65e 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
@@ -20,7 +20,6 @@
 
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.app.backup.BackupManager.OperationType;
@@ -30,8 +29,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.os.Process;
 import android.os.UserHandle;
@@ -41,7 +40,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.backup.UserBackupManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -540,9 +538,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -558,9 +556,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -635,9 +633,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -656,9 +654,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -677,9 +675,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {signature1Copy, signature2Copy},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -698,9 +696,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -719,9 +717,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -743,9 +741,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         new Signature[] {SIGNATURE_1, SIGNATURE_2}));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -770,9 +768,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         new Signature[] {SIGNATURE_1, SIGNATURE_2}));
         packageInfo.applicationInfo = new ApplicationInfo();
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index 5fcce67..e2536f8 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -39,8 +39,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.os.Bundle;
 import android.os.Process;
@@ -376,9 +376,9 @@
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {FAKE_SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         PackageManagerStub.sPackageInfo = packageInfo;
@@ -413,9 +413,9 @@
         packageInfo.applicationInfo.uid = Process.SYSTEM_UID;
         packageInfo.applicationInfo.backupAgentName = "backup.agent";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {FAKE_SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         PackageManagerStub.sPackageInfo = packageInfo;
@@ -451,9 +451,9 @@
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {FAKE_SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         PackageManagerStub.sPackageInfo = packageInfo;
@@ -492,9 +492,9 @@
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {FAKE_SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.versionCode = 2;
@@ -536,9 +536,9 @@
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {FAKE_SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.versionCode = 1;
@@ -576,9 +576,9 @@
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {FAKE_SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.versionCode = 1;
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index a19b387..363c26b 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -53,9 +52,7 @@
 import com.android.server.twilight.TwilightState;
 
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
@@ -76,25 +73,29 @@
     private int mUserId;
 
     private MockTwilightManager mTwilightManager;
+    private DisplayTransformManager mDisplayTransformManager;
 
     private ColorDisplayService mCds;
     private ColorDisplayService.BinderService mBinderService;
 
     private Resources mResourcesSpy;
 
-    @BeforeClass
-    public static void setDtm() {
-        final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
-        LocalServices.addService(DisplayTransformManager.class, dtm);
-    }
+    private static final int[] MINIMAL_COLOR_MODES = new int[] {
+        ColorDisplayManager.COLOR_MODE_NATURAL,
+        ColorDisplayManager.COLOR_MODE_BOOSTED,
+    };
 
     @Before
     public void setUp() {
         mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         doReturn(mContext).when(mContext).getApplicationContext();
 
-        mResourcesSpy = Mockito.spy(mContext.getResources());
-        when(mContext.getResources()).thenReturn(mResourcesSpy);
+        final Resources res = Mockito.spy(mContext.getResources());
+        doReturn(MINIMAL_COLOR_MODES).when(res).getIntArray(R.array.config_availableColorModes);
+        doReturn(true).when(res).getBoolean(R.bool.config_nightDisplayAvailable);
+        doReturn(true).when(res).getBoolean(R.bool.config_displayWhiteBalanceAvailable);
+        when(mContext.getResources()).thenReturn(res);
+        mResourcesSpy = res;
 
         mUserId = ActivityManager.getCurrentUser();
 
@@ -108,6 +109,10 @@
         mTwilightManager = new MockTwilightManager();
         LocalServices.addService(TwilightManager.class, mTwilightManager);
 
+        mDisplayTransformManager = Mockito.mock(DisplayTransformManager.class);
+        doReturn(true).when(mDisplayTransformManager).needsLinearColorMatrix();
+        LocalServices.addService(DisplayTransformManager.class, mDisplayTransformManager);
+
         mCds = new ColorDisplayService(mContext);
         mBinderService = mCds.new BinderService();
         LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
@@ -116,12 +121,18 @@
 
     @After
     public void tearDown() {
-        LocalServices.removeServiceForTest(TwilightManager.class);
-
+        /*
+         * Wait for internal {@link Handler} to finish processing pending messages, so that test
+         * code can safelyremove {@link DisplayTransformManager} mock from {@link LocalServices}.
+         */
+        mCds.mHandler.runWithScissors(() -> { /* nop */ }, /* timeout */ 1000);
         mCds = null;
 
+        LocalServices.removeServiceForTest(TwilightManager.class);
         mTwilightManager = null;
 
+        LocalServices.removeServiceForTest(DisplayTransformManager.class);
+
         mUserId = UserHandle.USER_NULL;
         mContext = null;
 
@@ -130,11 +141,6 @@
         LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
     }
 
-    @AfterClass
-    public static void removeDtm() {
-        LocalServices.removeServiceForTest(DisplayTransformManager.class);
-    }
-
     @Test
     public void customSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() {
         setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
@@ -1064,24 +1070,18 @@
 
     @Test
     public void compositionColorSpaces_noResources() {
-        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-        reset(dtm);
-
         when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
             .thenReturn(new int[] {});
         when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
             .thenReturn(new int[] {});
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
-        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
-                eq(Display.COLOR_MODE_INVALID));
+        verify(mDisplayTransformManager).setColorMode(
+                eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID));
     }
 
     @Test
     public void compositionColorSpaces_invalidResources() {
-        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-        reset(dtm);
-
         when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
             .thenReturn(new int[] {
                ColorDisplayManager.COLOR_MODE_NATURAL,
@@ -1094,15 +1094,12 @@
             });
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
-        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
-                eq(Display.COLOR_MODE_INVALID));
+        verify(mDisplayTransformManager).setColorMode(
+                eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID));
     }
 
     @Test
     public void compositionColorSpaces_validResources_validColorMode() {
-        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-        reset(dtm);
-
         when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
             .thenReturn(new int[] {
                ColorDisplayManager.COLOR_MODE_NATURAL
@@ -1113,15 +1110,12 @@
             });
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
-        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
-                eq(Display.COLOR_MODE_SRGB));
+        verify(mDisplayTransformManager).setColorMode(
+                eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_SRGB));
     }
 
     @Test
     public void compositionColorSpaces_validResources_invalidColorMode() {
-        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-        reset(dtm);
-
         when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
             .thenReturn(new int[] {
                ColorDisplayManager.COLOR_MODE_NATURAL
@@ -1132,8 +1126,8 @@
             });
         setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
         startService();
-        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(),
-                eq(Display.COLOR_MODE_INVALID));
+        verify(mDisplayTransformManager).setColorMode(
+                eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), eq(Display.COLOR_MODE_INVALID));
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 6cc8d471..a38a84b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -45,6 +45,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /** Tests for {@link ActiveSourceAction} */
 @SmallTest
@@ -76,7 +77,7 @@
                 mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService = new HdmiControlService(mContextSpy) {
+        mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
             AudioManager getAudioManager() {
                 return new AudioManager() {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 97bd066..5cf81ec 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -45,6 +45,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /** Tests for {@link ArcInitiationActionFromAvrTest} */
 @SmallTest
@@ -79,7 +80,7 @@
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiControlService hdmiControlService =
-                new HdmiControlService(mContextSpy) {
+                new HdmiControlService(mContextSpy, Collections.emptyList()) {
                     @Override
                     boolean isPowerStandby() {
                         return false;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 29c9b40..1462839 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -45,6 +45,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /** Tests for {@link ArcTerminationActionFromAvr} */
 @SmallTest
@@ -80,7 +81,7 @@
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiControlService hdmiControlService =
-                new HdmiControlService(mContextSpy) {
+                new HdmiControlService(mContextSpy, Collections.emptyList()) {
                     @Override
                     void wakeUp() {
                     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java
index 8b23be5..f49b1c1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java
@@ -34,6 +34,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.Collections;
+
 /** Tests for {@link DetectTvSystemAudioModeSupportAction} class. */
 @SmallTest
 @Presubmit
@@ -53,7 +55,8 @@
     public void SetUp() {
         mDeviceInfoForTests = new HdmiDeviceInfo(1001, 1234);
         HdmiControlService hdmiControlService =
-                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
 
                     @Override
                     void sendCecCommand(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index 650ffe9..fe8d691 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -51,6 +51,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /** Tests for {@link DevicePowerStatusAction} */
 @SmallTest
@@ -88,7 +89,7 @@
                 mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService = new HdmiControlService(mContextSpy) {
+        mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
             AudioManager getAudioManager() {
                 return new AudioManager() {
@@ -220,6 +221,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mPlaybackDevice.addAndStartAction(mDevicePowerStatusAction);
         mTestLooper.dispatchAll();
 
@@ -240,6 +242,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
                 .buildReportPhysicalAddressCommand(ADDR_TV, 0x0000, HdmiDeviceInfo.DEVICE_TV);
         mNativeWrapper.onCecMessage(reportPhysicalAddress);
@@ -263,6 +266,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
                 .buildReportPhysicalAddressCommand(ADDR_TV, 0x0000, HdmiDeviceInfo.DEVICE_TV);
         mNativeWrapper.onCecMessage(reportPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
index fa5cb67..0d5d05c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
@@ -54,6 +54,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 @SmallTest
 @RunWith(JUnit4.class)
@@ -105,7 +106,8 @@
         mMyLooper = mTestLooper.getLooper();
 
         mHdmiControlService =
-                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
                     @Override
                     boolean isControlEnabled() {
                         return true;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 41946fb..abc1468e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -69,12 +69,27 @@
                 R.bool.config_cecHdmiCecVersion20_default);
 
         doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRoutingControl_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRoutingControlEnabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecRoutingControlEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRoutingControlDisabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecRoutingControlDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecPowerControlMode_userConfigurable);
         doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecPowerControlModeTv_allowed);
-        doReturn(true).when(resources).getBoolean(
+        doReturn(false).when(resources).getBoolean(
                 R.bool.config_cecPowerControlModeTv_default);
         doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeTvAndAudioSystem_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecPowerControlModeTvAndAudioSystem_default);
+        doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecPowerControlModeBroadcast_allowed);
         doReturn(false).when(resources).getBoolean(
                 R.bool.config_cecPowerControlModeBroadcast_default);
@@ -95,6 +110,17 @@
                 R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
 
         doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioControl_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioControlEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioControlEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioControlDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecSystemAudioControlDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecSystemAudioModeMuting_userConfigurable);
         doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecSystemAudioModeMutingEnabled_allowed);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 1958cb0..d630ef6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -56,6 +56,7 @@
     private final Map<Integer, Boolean> mPortConnectionStatus = new HashMap<>();
     private final HashMap<Integer, Integer> mMessageSendResult = new HashMap<>();
     private int mMyPhysicalAddress = 0;
+    private int mVendorId = 0;
     private HdmiPortInfo[] mHdmiPortInfo = null;
     private HdmiCecController.HdmiCecCallback mCallback = null;
     private int mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
@@ -102,7 +103,7 @@
 
     @Override
     public int nativeGetVendorId() {
-        return 0;
+        return mVendorId;
     }
 
     @Override
@@ -181,6 +182,11 @@
     }
 
     @VisibleForTesting
+    protected void setVendorId(int vendorId) {
+        mVendorId = vendorId;
+    }
+
+    @VisibleForTesting
     protected void setPhysicalAddress(int physicalAddress) {
         mMyPhysicalAddress = physicalAddress;
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index 29f62b5..da10ec4 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -61,6 +62,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * Tests for the {@link HdmiCecAtomWriter} class and its usage by the HDMI-CEC framework.
@@ -103,7 +105,7 @@
                         mIThermalServiceMock, new Handler(mLooper)));
         doReturn(true).when(mIPowerManagerMock).isInteractive();
 
-        mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy));
+        mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.emptyList()));
         doNothing().when(mHdmiControlServiceSpy)
                 .writeStringSystemProperty(anyString(), anyString());
         doReturn(mHdmiCecAtomWriterSpy).when(mHdmiControlServiceSpy).getAtomWriter();
@@ -200,7 +202,7 @@
 
         mTestLooper.dispatchAll();
 
-        verify(mHdmiCecAtomWriterSpy, times(1)).messageReported(
+        verify(mHdmiCecAtomWriterSpy, atLeastOnce()).messageReported(
                 any(),
                 anyInt(),
                 eq(callerUid),
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index a37f94b..a94690e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -82,8 +82,10 @@
         assertThat(hdmiCecConfig.getAllSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                    HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
@@ -103,8 +105,10 @@
         assertThat(hdmiCecConfig.getUserSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+                    HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
@@ -125,7 +129,9 @@
         assertThat(hdmiCecConfig.getUserSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                    HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
@@ -188,6 +194,7 @@
         assertThat(hdmiCecConfig.getAllowedStringValues(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
                 .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
+                                 HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM,
                                  HdmiControlManager.POWER_CONTROL_MODE_BROADCAST,
                                  HdmiControlManager.POWER_CONTROL_MODE_NONE);
     }
@@ -199,6 +206,7 @@
         assertThat(hdmiCecConfig.getAllowedStringValues(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
                 .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
+                                 HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM,
                                  HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 
@@ -255,12 +263,12 @@
         HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getDefaultStringValue(
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
-                .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV);
+                .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM);
     }
 
     @Test
     public void getDefaultStringValue_WithOverride() {
-        setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+        setBooleanResource(R.bool.config_cecPowerControlModeTvAndAudioSystem_default, false);
         setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
         HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getDefaultStringValue(
@@ -277,7 +285,7 @@
 
     @Test
     public void getDefaultStringValue_NoDefault() {
-        setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+        setBooleanResource(R.bool.config_cecPowerControlModeTvAndAudioSystem_default, false);
         assertThrows(RuntimeException.class,
                 () -> new HdmiCecConfig(mContext, mStorageAdapter));
     }
@@ -334,7 +342,7 @@
     public void getStringValue_GlobalSetting_BasicSanity() {
         when(mStorageAdapter.retrieveGlobalSetting(
                   Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
-                  HdmiControlManager.POWER_CONTROL_MODE_TV))
+                  HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM))
             .thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
         assertThat(hdmiCecConfig.getStringValue(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index ee1a857..bd6e46d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -69,6 +69,7 @@
 import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Optional;
 
 /** Tests for {@link com.android.server.hdmi.HdmiCecController} class. */
@@ -99,7 +100,7 @@
         mMyLooper = mTestLooper.getLooper();
 
         mHdmiControlServiceSpy = spy(new HdmiControlService(
-                InstrumentationRegistry.getTargetContext()));
+                InstrumentationRegistry.getTargetContext(), Collections.emptyList()));
         doReturn(mMyLooper).when(mHdmiControlServiceSpy).getIoLooper();
         doReturn(mMyLooper).when(mHdmiControlServiceSpy).getServiceLooper();
         doAnswer(__ -> mCecVersion).when(mHdmiControlServiceSpy).getCecVersion();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 7911c40..e03e1be 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -53,6 +53,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 @SmallTest
 @Presubmit
@@ -96,7 +97,8 @@
         mMyLooper = mTestLooper.getLooper();
 
         mHdmiControlService =
-            new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+            new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                    Collections.emptyList()) {
                 @Override
                 AudioManager getAudioManager() {
                     return new AudioManager() {
@@ -210,7 +212,7 @@
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
         mLocalDevices.add(mHdmiCecLocalDevicePlayback);
-        mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnables(true);
+        mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnabled(true);
         mHdmiPortInfo = new HdmiPortInfo[4];
         mHdmiPortInfo[0] =
             new HdmiPortInfo(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 524ad62..99e3d68 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -53,6 +53,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
@@ -94,7 +95,8 @@
         mMyLooper = mTestLooper.getLooper();
 
         mHdmiControlService =
-                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
                     @Override
                     void wakeUp() {
                         mWokenUp = true;
@@ -694,20 +696,45 @@
                 HdmiControlManager.POWER_CONTROL_MODE_TV);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
         HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
+    }
+
+    @Test
+    public void handleOnStandby_ScreenOff_NotActiveSource_ToTvAndAudioSystem() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM);
+        mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
+                "HdmiCecLocalDevicePlaybackTest");
+        mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
+        HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
@@ -719,20 +746,20 @@
                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
         HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
@@ -744,20 +771,20 @@
                 HdmiControlManager.POWER_CONTROL_MODE_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
         HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
@@ -769,20 +796,45 @@
                 HdmiControlManager.POWER_CONTROL_MODE_TV);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
         HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
+    }
+
+    @Test
+    public void handleOnStandby_ScreenOff_ActiveSource_ToTvAndAudioSystem() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+        mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
+        HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+
+        assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageToAudioSystem);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
@@ -794,20 +846,20 @@
                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
         HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
         assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageBroadcast);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
@@ -819,20 +871,20 @@
                 HdmiControlManager.POWER_CONTROL_MODE_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageToAudioSystem = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_AUDIO_SYSTEM);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
         HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
                 mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToAudioSystem);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
         assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSource);
     }
@@ -844,9 +896,6 @@
                 HdmiControlManager.POWER_CONTROL_MODE_TV);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
-        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
         mHdmiCecLocalDevicePlayback.onStandby(true, HdmiControlService.STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
 
@@ -1456,7 +1505,7 @@
     }
 
     @Test
-    public void oneTouchPlay_SendStandbyOnSleepToTv() {
+    public void oneTouchPlay_PowerControlModeToTv() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 HdmiControlManager.POWER_CONTROL_MODE_TV);
@@ -1479,7 +1528,30 @@
     }
 
     @Test
-    public void oneTouchPlay_SendStandbyOnSleepBroadcast() {
+    public void oneTouchPlay_PowerControlModeToTvAndAudioSystem() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM);
+        mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+            }
+        });
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+                ADDR_TV);
+        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+        HdmiCecMessage systemAudioModeRequest = HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+                mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, mPlaybackPhysicalAddress, true);
+        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+        assertThat(mNativeWrapper.getResultMessages()).contains(systemAudioModeRequest);
+    }
+
+    @Test
+    public void oneTouchPlay_PowerControlModeBroadcast() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
@@ -1502,7 +1574,7 @@
     }
 
     @Test
-    public void oneTouchPlay_SendStandbyOnSleepNone() {
+    public void oneTouchPlay_PowerControlModeNone() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 HdmiControlManager.POWER_CONTROL_MODE_NONE);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 6502e48..7057c50 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -40,6 +40,7 @@
 import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.Result;
 import android.media.AudioManager;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
@@ -141,7 +142,7 @@
         Context context = InstrumentationRegistry.getTargetContext();
 
         mHdmiControlService =
-                new HdmiControlService(context) {
+                new HdmiControlService(context, Collections.emptyList()) {
                     @Override
                     boolean isControlEnabled() {
                         return isControlEnabled;
@@ -205,6 +206,7 @@
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mNativeWrapper.setPhysicalAddress(0x2000);
         mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
     }
 
     @Test
@@ -243,15 +245,37 @@
 
     @Test
     public void handleGiveDeviceVendorId_success() {
-        mSrcAddr = ADDR_UNREGISTERED;
-        mDesAddr = ADDR_BROADCAST;
-        /** nativeGetVendorId returns 0 */
-        param = new byte[] {(byte) ((0 >> 8) & 0xFF), (byte) (0 & 0xFF), (byte) (0 & 0xFF)};
-        callbackResult = -1;
-        mHdmiLocalDevice.handleGiveDeviceVendorId(
-                (int finalResult) -> callbackResult = finalResult);
+        /** Set vendor id to 0 */
+        mNativeWrapper.setVendorId(0);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildDeviceVendorIdCommand(ADDR_TV, 0);
+        @Constants.HandleMessageResult
+        int handleResult =
+                mHdmiLocalDevice.handleGiveDeviceVendorId(
+                        HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(
+                                ADDR_PLAYBACK_1, ADDR_TV));
         mTestLooper.dispatchAll();
-        assertEquals(0, callbackResult);
+        assertEquals(Constants.HANDLED, handleResult);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    @Test
+    public void handleGiveDeviceVendorId_failure() {
+        mNativeWrapper.setVendorId(Result.FAILURE_UNKNOWN);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                        ADDR_TV,
+                        ADDR_PLAYBACK_1,
+                        Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID,
+                        Constants.ABORT_UNABLE_TO_DETERMINE);
+        @Constants.HandleMessageResult
+        int handleResult =
+                mHdmiLocalDevice.handleGiveDeviceVendorId(
+                        HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(
+                                ADDR_PLAYBACK_1, ADDR_TV));
+        mTestLooper.dispatchAll();
+        assertEquals(Constants.HANDLED, handleResult);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 59711a6..5a2f7bb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -56,6 +56,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 @SmallTest
 @RunWith(JUnit4.class)
@@ -88,7 +89,8 @@
         mMyLooper = mTestLooper.getLooper();
 
         mHdmiControlService =
-                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
                     @Override
                     void wakeUp() {
                         mWokenUp = true;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index 2307a85..ebd8d77 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -37,6 +37,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.Collections;
+
 /** Tests for {@link com.android.server.hdmi.HdmiCecMessageValidator} class. */
 @SmallTest
 @Presubmit
@@ -49,7 +51,7 @@
     @Before
     public void setUp() throws Exception {
         HdmiControlService mHdmiControlService = new HdmiControlService(
-                InstrumentationRegistry.getTargetContext());
+                InstrumentationRegistry.getTargetContext(), Collections.emptyList());
 
         mHdmiControlService.setIoLooper(mTestLooper.getLooper());
         mHdmiCecMessageValidator = new HdmiCecMessageValidator(mHdmiControlService);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
index b1998f5..e7d1b95 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java
@@ -64,7 +64,7 @@
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
-        mHdmiControlService = new HdmiControlService(mContext) {
+        mHdmiControlService = new HdmiControlService(mContext, Collections.emptyList()) {
             @Override
             void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
                 mDeviceEventListenerStatuses.add(status);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 572ffd9..dc633a2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -47,6 +47,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 @SmallTest
 @Presubmit
@@ -83,7 +84,7 @@
                 mIThermalServiceMock, new Handler(myLooper)));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService = new HdmiControlService(contextSpy) {
+        mHdmiControlService = new HdmiControlService(contextSpy, Collections.emptyList()) {
             @Override
             boolean isControlEnabled() {
                 return true;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index f53ae52..755eef3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -63,6 +63,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Optional;
 
 /**
@@ -205,7 +206,7 @@
 
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
 
-        mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy));
+        mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.emptyList()));
         doNothing().when(mHdmiControlServiceSpy)
                 .writeStringSystemProperty(anyString(), anyString());
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index b820df3..9466f52 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -91,8 +91,6 @@
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
 
-        setHdmiControlEnabled(hdmiControlEnabled);
-
         when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
                 new PowerManager(mContextSpy, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
@@ -137,6 +135,7 @@
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
         mHdmiControlService.setHdmiCecConfig(mHdmiCecConfig);
+        setHdmiControlEnabled(hdmiControlEnabled);
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
new file mode 100644
index 0000000..bd307fd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
+import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+import static com.android.server.hdmi.Constants.MESSAGE_ACTIVE_SOURCE;
+import static com.android.server.hdmi.Constants.MESSAGE_ROUTING_INFORMATION;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+import static com.android.server.hdmi.RoutingControlAction.STATE_WAIT_FOR_ROUTING_INFORMATION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.HdmiCecFeatureAction.ActionTimer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class RoutingControlActionTest {
+    /*
+     * Example connection diagram used in tests. Double-lined paths indicate the currently active
+     * routes.
+     *
+     *
+     *                              +-----------+
+     *                              |    TV     |
+     *                              |  0.0.0.0  |
+     *                              +---+-----+-+
+     *                                  |     |
+     *                               <----------+ 1) AVR -> Switch
+     *             +----------+         |     |  +-----------+
+     *             | AVR      +---------+     +--+ Switch    |
+     *             | 1.0.0.0  |                  | 2.0.0.0   |
+     *             +--+---++--+                  +--++-----+-+  <-------+ 2) Recorder -> Blu-ray
+     *                |   ||                        ||     |
+     *                |   ||                        ||     +--------+
+     * +-----------+  |   ||  +----------+     +----++----+         |
+     * | XBox      +--+   ++--+ Tuner    |     | Blueray  |   +-----+----+
+     * | 1.1.0.0   |          | 1.2.0.0  |     | 2.1.0.0  |   | Recorder |
+     * +-----------+          +----++----+     +----------+   | 2.2.0.0  |
+     *                             ||                         +----------+
+     *                             ||
+     *                        +----++----+
+     *                        | Player   |
+     *                        | 1.2.1.0  |
+     *                        +----------+
+     *
+     */
+
+    private static final int PHYSICAL_ADDRESS_TV = 0x0000;
+    private static final int PHYSICAL_ADDRESS_AVR = 0x1000;
+    private static final int PHYSICAL_ADDRESS_SWITCH = 0x2000;
+    private static final int PHYSICAL_ADDRESS_TUNER = 0x1200;
+    private static final int PHYSICAL_ADDRESS_PLAYER = 0x1210;
+    private static final int PHYSICAL_ADDRESS_BLUERAY = 0x2100;
+    private static final int PHYSICAL_ADDRESS_RECORDER = 0x2200;
+    private static final int PORT_1 = 1;
+    private static final int PORT_2 = 2;
+    private static final int VENDOR_ID_AVR = 0x11233;
+
+    private static final byte[] TUNER_PARAM =
+            new byte[] {(PHYSICAL_ADDRESS_TUNER >> 8) & 0xFF, PHYSICAL_ADDRESS_TUNER & 0xFF};
+    private static final byte[] PLAYER_PARAM =
+            new byte[] {(PHYSICAL_ADDRESS_PLAYER >> 8) & 0xFF, PHYSICAL_ADDRESS_PLAYER & 0xFF};
+
+    private static final HdmiDeviceInfo DEVICE_INFO_AVR =
+            new HdmiDeviceInfo(ADDR_AUDIO_SYSTEM, PHYSICAL_ADDRESS_AVR, PORT_1,
+                    HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, VENDOR_ID_AVR, "Audio");
+    private static final HdmiDeviceInfo DEVICE_INFO_PLAYER =
+            new HdmiDeviceInfo(ADDR_PLAYBACK_1, PHYSICAL_ADDRESS_PLAYER, PORT_1,
+                    HdmiDeviceInfo.DEVICE_PLAYBACK, VENDOR_ID_AVR, "Player");
+    private static final HdmiCecMessage ROUTING_INFORMATION_TUNER = new HdmiCecMessage(
+            ADDR_UNREGISTERED, ADDR_BROADCAST, MESSAGE_ROUTING_INFORMATION, TUNER_PARAM);
+    private static final HdmiCecMessage ROUTING_INFORMATION_PLAYER = new HdmiCecMessage(
+            ADDR_UNREGISTERED, ADDR_BROADCAST, MESSAGE_ROUTING_INFORMATION, PLAYER_PARAM);
+    private static final HdmiCecMessage ACTIVE_SOURCE_TUNER = new HdmiCecMessage(
+            ADDR_TUNER_1, ADDR_BROADCAST, MESSAGE_ACTIVE_SOURCE, TUNER_PARAM);
+    private static final HdmiCecMessage ACTIVE_SOURCE_PLAYER = new HdmiCecMessage(
+            ADDR_PLAYBACK_1, ADDR_BROADCAST, MESSAGE_ACTIVE_SOURCE, PLAYER_PARAM);
+
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
+    private FakeNativeWrapper mNativeWrapper;
+    private Looper mMyLooper;
+    private TestLooper mTestLooper = new TestLooper();
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+
+    @Mock
+    private IPowerManager mIPowerManagerMock;
+    @Mock
+    private IThermalService mIThermalServiceMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = InstrumentationRegistry.getTargetContext();
+        mMyLooper = mTestLooper.getLooper();
+        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mMyLooper));
+
+        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
+
+        mHdmiControlService =
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
+                    @Override
+                    boolean isControlEnabled() {
+                        return true;
+                    }
+
+                    @Override
+                    void wakeUp() {
+                    }
+
+                    @Override
+                    protected void writeStringSystemProperty(String key, String value) {
+                        // do nothing
+                    }
+
+                    @Override
+                    boolean isPowerStandbyOrTransient() {
+                        return false;
+                    }
+
+                    @Override
+                    protected PowerManager getPowerManager() {
+                        return powerManager;
+                    }
+
+                    @Override
+                    protected HdmiCecConfig getHdmiCecConfig() {
+                        return hdmiCecConfig;
+                    }
+                };
+
+        mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
+        mHdmiCecLocalDeviceTv.init();
+        mHdmiControlService.setIoLooper(mMyLooper);
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+                mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mLocalDevices.add(mHdmiCecLocalDeviceTv);
+        HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
+        hdmiPortInfos[0] =
+                new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_AVR,
+                                 true, false, false);
+        mNativeWrapper.setPortInfo(hdmiPortInfos);
+        mHdmiControlService.initService();
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mNativeWrapper.setPhysicalAddress(0x0000);
+        mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR);
+    }
+
+    private static class TestActionTimer implements ActionTimer {
+        private int mState;
+
+        @Override
+        public void sendTimerMessage(int state, long delayMillis) {
+            mState = state;
+        }
+
+        @Override
+        public void clearTimerMessage() {
+        }
+
+        private int getState() {
+            return mState;
+        }
+    }
+
+    private static class TestInputSelectCallback extends IHdmiControlCallback.Stub {
+        private final List<Integer> mCallbackResult = new ArrayList<Integer>();
+
+        @Override
+        public void onComplete(int result) {
+            mCallbackResult.add(result);
+        }
+
+        private int getResult() {
+            assert (mCallbackResult.size() == 1);
+            return mCallbackResult.get(0);
+        }
+    }
+
+    private static RoutingControlAction createRoutingControlAction(HdmiCecLocalDeviceTv localDevice,
+            TestInputSelectCallback callback) {
+        return new RoutingControlAction(localDevice, PHYSICAL_ADDRESS_AVR, callback);
+    }
+
+    // Routing control succeeds against the device connected directly to the port. Action
+    // won't get any <Routing Information> in this case. It times out on <Routing Information>,
+    // regards the directly connected one as the new routing path to switch to.
+    @Test
+    public void testRoutingControl_succeedForDirectlyConnectedDevice() {
+        TestInputSelectCallback callback = new TestInputSelectCallback();
+        TestActionTimer actionTimer = new TestActionTimer();
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR);
+
+        RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback);
+        action.setActionTimer(actionTimer);
+        action.start();
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION);
+
+        action.handleTimerEvent(actionTimer.getState());
+        mTestLooper.dispatchAll();
+        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+                        ADDR_TV, PHYSICAL_ADDRESS_AVR);
+        assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+    }
+
+    // Succeeds by receiving a couple of <Routing Information> commands, followed by
+    // <Set Stream Path> going out in the end.
+    @Test
+    public void testRoutingControl_succeedForDeviceBehindSwitch() {
+        TestInputSelectCallback callback = new TestInputSelectCallback();
+        TestActionTimer actionTimer = new TestActionTimer();
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_PLAYER);
+        RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback);
+        action.setActionTimer(actionTimer);
+        action.start();
+
+        assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION);
+
+        action.processCommand(ROUTING_INFORMATION_TUNER);
+        action.processCommand(ROUTING_INFORMATION_PLAYER);
+
+        action.handleTimerEvent(actionTimer.getState());
+        mTestLooper.dispatchAll();
+        HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+                        ADDR_TV, PHYSICAL_ADDRESS_PLAYER);
+        assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
index 2cf4ef1..290e4b0 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
@@ -48,6 +48,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * Test for {@link SystemAudioAutoInitiationAction}.
@@ -86,7 +87,7 @@
                 mIThermalServiceMock, new Handler(myLooper)));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService = new HdmiControlService(mContextSpy) {
+        mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
             @Override
             AudioManager getAudioManager() {
                 return new AudioManager() {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index e82c788..2019a16 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -38,6 +38,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.Collections;
+
 /** Tests for {@link SystemAudioInitiationActionFromAvr} */
 @SmallTest
 @Presubmit
@@ -65,7 +67,8 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
 
-        HdmiControlService hdmiControlService = new HdmiControlService(context) {
+        HdmiControlService hdmiControlService = new HdmiControlService(context,
+                Collections.emptyList()) {
                     @Override
                     void sendCecCommand(
                             HdmiCecMessage command, @Nullable SendMessageCallback callback) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index dc745cd..be942d6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -30,9 +30,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.UserInfo;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.component.ParsedActivity;
@@ -83,17 +82,9 @@
     private static final int DUMMY_OVERLAY_APPID = 10756;
     private static final int SYSTEM_USER = 0;
     private static final int SECONDARY_USER = 10;
-    private static final int ADDED_USER = 11;
     private static final int[] USER_ARRAY = {SYSTEM_USER, SECONDARY_USER};
-    private static final int[] USER_ARRAY_WITH_ADDED = {SYSTEM_USER, SECONDARY_USER, ADDED_USER};
-    private static final UserInfo[] USER_INFO_LIST = toUserInfos(USER_ARRAY);
-    private static final UserInfo[] USER_INFO_LIST_WITH_ADDED = toUserInfos(USER_ARRAY_WITH_ADDED);
-
-    private static UserInfo[] toUserInfos(int[] userIds) {
-        return Arrays.stream(userIds)
-                .mapToObj(id -> new UserInfo(id, Integer.toString(id), 0))
-                .toArray(UserInfo[]::new);
-    }
+    private static final UserInfo[] USER_INFO_LIST = Arrays.stream(USER_ARRAY).mapToObj(
+            id -> new UserInfo(id, Integer.toString(id), 0)).toArray(UserInfo[]::new);
 
     @Mock
     AppsFilter.FeatureConfig mFeatureConfigMock;
@@ -260,8 +251,8 @@
         final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
         watcher.register();
         final Signature frameworkSignature = Mockito.mock(Signature.class);
-        final PackageParser.SigningDetails frameworkSigningDetails =
-                new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
+        final SigningDetails frameworkSigningDetails =
+                new SigningDetails(new Signature[]{frameworkSignature}, 1);
         final ParsingPackage android = pkg("android");
         watcher.verifyNoChangeReported("prepare");
         android.addProtectedBroadcast("TEST_ACTION");
@@ -327,47 +318,6 @@
     }
 
     @Test
-    public void testOnUserCreated_FilterMatches() throws Exception {
-        final AppsFilter appsFilter =
-                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
-                        mMockExecutor);
-        simulateAddBasicAndroid(appsFilter);
-
-        appsFilter.onSystemReady();
-
-        PackageSetting target = simulateAddPackage(appsFilter,
-                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
-        PackageSetting calling = simulateAddPackage(appsFilter,
-                pkgQueriesProvider("com.some.other.package", "com.some.authority"),
-                DUMMY_CALLING_APPID);
-
-        for (int subjectUserId : USER_ARRAY) {
-            for (int otherUserId : USER_ARRAY) {
-                assertFalse(appsFilter.shouldFilterApplication(
-                        UserHandle.getUid(DUMMY_CALLING_APPID, subjectUserId), calling, target,
-                        otherUserId));
-            }
-        }
-
-        // adds new user
-        doAnswer(invocation -> {
-            ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
-                    .currentState(mExisting, USER_INFO_LIST_WITH_ADDED);
-            return new Object();
-        }).when(mStateProvider)
-                .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
-        appsFilter.onUserCreated(ADDED_USER);
-
-        for (int subjectUserId : USER_ARRAY_WITH_ADDED) {
-            for (int otherUserId : USER_ARRAY_WITH_ADDED) {
-                assertFalse(appsFilter.shouldFilterApplication(
-                        UserHandle.getUid(DUMMY_CALLING_APPID, subjectUserId), calling, target,
-                        otherUserId));
-            }
-        }
-    }
-
-    @Test
     public void testQueriesDifferentProvider_Filters() throws Exception {
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
@@ -641,12 +591,12 @@
         appsFilter.onSystemReady();
 
         final Signature frameworkSignature = Mockito.mock(Signature.class);
-        final PackageParser.SigningDetails frameworkSigningDetails =
-                new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
+        final SigningDetails frameworkSigningDetails =
+                new SigningDetails(new Signature[]{frameworkSignature}, 1);
 
         final Signature otherSignature = Mockito.mock(Signature.class);
-        final PackageParser.SigningDetails otherSigningDetails =
-                new PackageParser.SigningDetails(new Signature[]{otherSignature}, 1);
+        final SigningDetails otherSigningDetails =
+                new SigningDetails(new Signature[]{otherSignature}, 1);
 
         simulateAddPackage(appsFilter, pkg("android"), 1000,
                 b -> b.setSigningDetails(frameworkSigningDetails));
@@ -1248,8 +1198,8 @@
 
     private void simulateAddBasicAndroid(AppsFilter appsFilter) throws Exception {
         final Signature frameworkSignature = Mockito.mock(Signature.class);
-        final PackageParser.SigningDetails frameworkSigningDetails =
-                new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
+        final SigningDetails frameworkSigningDetails =
+                new SigningDetails(new Signature[]{frameworkSignature}, 1);
         final ParsingPackage android = pkg("android");
         simulateAddPackage(appsFilter, android, 1000,
                 b -> b.setSigningDetails(frameworkSigningDetails));
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index c572dd6..4f77afb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -77,12 +77,12 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
@@ -1413,9 +1413,9 @@
         pi.applicationInfo.setVersionCode(version);
         pi.signatures = null;
         pi.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         genSignatures(signatures),
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         return pi;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 128cbaa..a710839 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.server.pm;
 
+import static android.content.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -25,6 +29,7 @@
 
 import static java.lang.Boolean.TRUE;
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static java.util.stream.Collectors.toList;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -35,10 +40,10 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedComponent;
@@ -83,6 +88,7 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -106,6 +112,7 @@
     private static final String TEST_APP2_APK = "PackageParserTestApp2.apk";
     private static final String TEST_APP3_APK = "PackageParserTestApp3.apk";
     private static final String TEST_APP4_APK = "PackageParserTestApp4.apk";
+    private static final String TEST_APP5_APK = "PackageParserTestApp5.apk";
     private static final String PACKAGE_NAME = "com.android.servicestests.apps.packageparserapp";
 
     @Before
@@ -506,6 +513,56 @@
         }
     }
 
+    @Test
+    public void testParseModernPackageHasNoCompatPermissions() throws Exception {
+        final File testFile = extractFile(TEST_APP1_APK);
+        try {
+            final ParsedPackage pkg = new TestPackageParser2()
+                    .parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
+            final List<String> compatPermissions =
+                    Arrays.stream(COMPAT_PERMS).map(p -> p.name).collect(toList());
+            assertWithMessage(
+                    "Compatibility permissions shouldn't be added into uses permissions.")
+                    .that(pkg.getUsesPermissions().stream().map(p -> p.name).collect(toList()))
+                    .containsNoneIn(compatPermissions);
+            assertWithMessage(
+                    "Compatibility permissions shouldn't be added into requested permissions.")
+                    .that(pkg.getRequestedPermissions()).containsNoneIn(compatPermissions);
+            assertWithMessage(
+                    "Compatibility permissions shouldn't be added into implicit permissions.")
+                    .that(pkg.getImplicitPermissions()).containsNoneIn(compatPermissions);
+        } finally {
+            testFile.delete();
+        }
+    }
+
+    @Test
+    public void testParseLegacyPackageHasCompatPermissions() throws Exception {
+        final File testFile = extractFile(TEST_APP5_APK);
+        try {
+            final ParsedPackage pkg = new TestPackageParser2()
+                    .parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
+            assertWithMessage(
+                    "Compatibility permissions should be added into uses permissions.")
+                    .that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
+                            .allMatch(pkg.getUsesPermissions().stream().map(p -> p.name)
+                            .collect(toList())::contains))
+                    .isTrue();
+            assertWithMessage(
+                    "Compatibility permissions should be added into requested permissions.")
+                    .that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
+                            .allMatch(pkg.getRequestedPermissions()::contains))
+                    .isTrue();
+            assertWithMessage(
+                    "Compatibility permissions should be added into implicit permissions.")
+                    .that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
+                            .allMatch(pkg.getImplicitPermissions()::contains))
+                    .isTrue();
+        } finally {
+            testFile.delete();
+        }
+    }
+
     /**
      * A trivial subclass of package parser that only caches the package name, and throws away
      * all other information.
@@ -645,7 +702,8 @@
         assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
         assertEquals(a.getVersionName(), b.getVersionName());
         assertEquals(a.getSharedUserId(), b.getSharedUserId());
-        assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures);
+        assertArrayEquals(a.getSigningDetails().getSignatures(),
+                b.getSigningDetails().getSignatures());
         assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
         assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
         assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
@@ -653,7 +711,7 @@
         assertEquals(a.getOverlayCategory(), b.getOverlayCategory());
         assertEquals(a.getOverlayPriority(), b.getOverlayPriority());
         assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic());
-        assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys);
+        assertEquals(a.getSigningDetails().getPublicKeys(), b.getSigningDetails().getPublicKeys());
         assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets());
         assertEquals(a.getKeySetMapping(), b.getKeySetMapping());
         assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash());
@@ -873,9 +931,9 @@
                 .setVersionName("foo17")
                 .setSharedUserId("foo18")
                 .setSigningDetails(
-                        new PackageParser.SigningDetails(
+                        new SigningDetails(
                                 new Signature[]{new Signature(new byte[16])},
-                                2,
+                                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2,
                                 new ArraySet<>(),
                                 null)
                 )
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index f75751b..f551ad1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -16,8 +16,8 @@
 
 package com.android.server.pm;
 
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
+import android.content.pm.SigningDetails;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
@@ -47,7 +47,7 @@
     private String[] mUsesStaticLibraries;
     private long[] mUsesStaticLibrariesVersions;
     private Map<String, ArraySet<String>> mMimeGroups;
-    private PackageParser.SigningDetails mSigningDetails;
+    private SigningDetails mSigningDetails;
     private UUID mDomainSetId = UUID.randomUUID();
 
     public PackageSettingBuilder setPackage(AndroidPackage pkg) {
@@ -159,7 +159,7 @@
     }
 
     public PackageSettingBuilder setSigningDetails(
-            PackageParser.SigningDetails signingDetails) {
+            SigningDetails signingDetails) {
         mSigningDetails = signingDetails;
         return this;
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index 27f3eec..b9431bf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -22,11 +22,9 @@
 import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.util.TypedXmlPullParser;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.InstrumentationRegistry;
@@ -39,7 +37,6 @@
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 
-import java.io.File;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -107,10 +104,10 @@
     }
 
     private static final int[] CAPABILITIES =
-            {PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA,
-                    PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID,
-                    PackageParser.SigningDetails.CertCapabilities.PERMISSION,
-                    PackageParser.SigningDetails.CertCapabilities.ROLLBACK};
+            {SigningDetails.CertCapabilities.INSTALLED_DATA,
+                    SigningDetails.CertCapabilities.SHARED_USER_ID,
+                    SigningDetails.CertCapabilities.PERMISSION,
+                    SigningDetails.CertCapabilities.ROLLBACK};
 
     @Before
     public void setUp() throws Exception {
@@ -173,7 +170,7 @@
         assertEquals(
                 "The signing details was not UNKNOWN after parsing an invalid public key cert key"
                         + " attribute",
-                PackageParser.SigningDetails.UNKNOWN, mPackageSetting.signatures.mSigningDetails);
+                SigningDetails.UNKNOWN, mPackageSetting.signatures.mSigningDetails);
     }
 
     @Test
@@ -181,14 +178,14 @@
         // Verifies if the sigs count attribute is missing then the signature cannot be read but the
         // method does not throw an exception.
         verifyReadXmlReturnsExpectedSignatures("xml/one-signer-missing-sigs-count.xml",
-                PackageParser.SigningDetails.SignatureSchemeVersion.UNKNOWN);
+                SigningDetails.SignatureSchemeVersion.UNKNOWN);
     }
 
     @Test
     public void testReadXmlWithMissingSchemeVersion() throws Exception {
         // Verifies if the schemeVersion is an invalid value the signature can still be obtained.
         verifyReadXmlReturnsExpectedSignatures("xml/one-signer-missing-scheme-version.xml",
-                PackageParser.SigningDetails.SignatureSchemeVersion.UNKNOWN,
+                SigningDetails.SignatureSchemeVersion.UNKNOWN,
                 FIRST_EXPECTED_SIGNATURE);
     }
 
@@ -198,7 +195,7 @@
         // obtained.
         verifyReadXmlReturnsExpectedSignaturesAndLineage(
                 "xml/three-signers-in-lineage-missing-scheme-version.xml",
-                PackageParser.SigningDetails.SignatureSchemeVersion.UNKNOWN,
+                SigningDetails.SignatureSchemeVersion.UNKNOWN,
                 FIRST_EXPECTED_SIGNATURE, SECOND_EXPECTED_SIGNATURE, THIRD_EXPECTED_SIGNATURE);
     }
 
@@ -386,7 +383,7 @@
         verifySignaturesContainExpectedValues(signatures, expectedSignatures);
         assertEquals("The returned signature scheme is not the expected value",
                 expectedSchemeVersion,
-                mPackageSetting.signatures.mSigningDetails.signatureSchemeVersion);
+                mPackageSetting.signatures.mSigningDetails.getSignatureSchemeVersion());
     }
 
     /**
@@ -402,7 +399,7 @@
         Set<String> expectedSignatures = createSetOfSignatures(expectedSignatureValues);
         verifySignaturesContainExpectedValues(signatures, expectedSignatures);
         assertEquals("The returned signature scheme is not the expected value", schemeVersion,
-                mPackageSetting.signatures.mSigningDetails.signatureSchemeVersion);
+                mPackageSetting.signatures.mSigningDetails.getSignatureSchemeVersion());
         for (Signature signature : signatures) {
             String signatureValue = HexDump.toHexString(signature.toByteArray(), false);
             int expectedCapabilities = SIGNATURE_TO_CAPABILITY_MAP.get(signatureValue);
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index f1930d7..cee4cda 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -91,6 +91,16 @@
     }
 
     @Test
+    public void getSeInfoTargetingCurDevelopment() {
+        AndroidPackage pkg = makePackage(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(true);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=" + Build.VERSION_CODES.CUR_DEVELOPMENT));
+    }
+
+    @Test
     public void getSeInfoNoOptInButAlreadyR() {
         AndroidPackage pkg = makePackage(R_OPT_IN_VERSION);
         when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_R_CHANGES),
diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
index 182760b..b447857 100644
--- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
@@ -25,8 +25,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
 import android.platform.test.annotations.Presubmit;
 import android.test.MoreAsserts;
@@ -95,9 +95,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -114,9 +114,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -197,9 +197,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -219,9 +219,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -240,9 +240,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -262,9 +262,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -285,9 +285,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -309,9 +309,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -336,9 +336,9 @@
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.packageName = "test";
         packageInfo.signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
+                new SigningDetails(
                         new Signature[] {SIGNATURE_1, SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
                         null,
                         null));
         packageInfo.applicationInfo = new ApplicationInfo();
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 4618157..2a4c3fd 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -32,6 +32,7 @@
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
+import android.util.SparseIntArray;
 
 import com.android.server.pm.ApexManager;
 import com.android.server.pm.Installer;
@@ -119,8 +120,9 @@
     }
 
     private static Rollback createRollbackForId(int rollbackId) {
-        return new Rollback(rollbackId, new File("/does/not/exist"), -1,
-                0, "com.xyz");
+        return new Rollback(rollbackId, new File("/does/not/exist"), -1, /* isStaged */ false, 0,
+                "com.xyz", null, new SparseIntArray(0));
+
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
index c42f936..9d56a36 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
@@ -82,7 +82,7 @@
             + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
             + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
             + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
-            + "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1,"
+            + "'originalSessionId':567,'state':'enabling','apkSessionId':-1,"
             + "'restoreUserDataInProgress':true, 'userId':0,"
             + "'installerPackageName':'some.installer'}";
 
@@ -102,7 +102,7 @@
             + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
             + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
             + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
-            + "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1,"
+            + "'originalSessionId':567,'state':'enabling','apkSessionId':-1,"
             + "'restoreUserDataInProgress':true, 'userId':0,"
             + "'installerPackageName':'some.installer',"
             + "'extensionVersions':[{'sdkVersion':5,'extensionVersion':25},"
@@ -129,12 +129,13 @@
         SparseIntArray extensionVersions = new SparseIntArray();
         extensionVersions.put(30, 71);
         Rollback rollback = mRollbackStore.createNonStagedRollback(
-                ID, USER, INSTALLER, null, extensionVersions);
+                ID, 567, USER, INSTALLER, null, extensionVersions);
 
         assertThat(rollback.getBackupDir().getAbsolutePath())
                 .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID);
 
         assertThat(rollback.isStaged()).isFalse();
+        assertThat(rollback.getOriginalSessionId()).isEqualTo(567);
         assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
         assertThat(rollback.info.getPackages()).isEmpty();
         assertThat(rollback.isEnabling()).isTrue();
@@ -153,7 +154,7 @@
                 .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID);
 
         assertThat(rollback.isStaged()).isTrue();
-        assertThat(rollback.getStagedSessionId()).isEqualTo(897);
+        assertThat(rollback.getOriginalSessionId()).isEqualTo(897);
 
         assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
         assertThat(rollback.info.getPackages()).isEmpty();
@@ -168,7 +169,7 @@
         extensionVersions.put(5, 25);
         extensionVersions.put(30, 71);
         Rollback origRb = mRollbackStore.createNonStagedRollback(
-                ID, USER, INSTALLER, null, extensionVersions);
+                ID, 567, USER, INSTALLER, null, extensionVersions);
 
         origRb.setRestoreUserDataInProgress(true);
         origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2));
@@ -218,7 +219,7 @@
     @Test
     public void loadFromJsonNoExtensionVersions() throws Exception {
         Rollback expectedRb = mRollbackStore.createNonStagedRollback(
-                ID, USER, INSTALLER, null, new SparseIntArray(0));
+                ID, 567, USER, INSTALLER, null, new SparseIntArray(0));
 
         expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
         expectedRb.setRestoreUserDataInProgress(true);
@@ -268,7 +269,7 @@
         extensionVersions.put(5, 25);
         extensionVersions.put(30, 71);
         Rollback expectedRb = mRollbackStore.createNonStagedRollback(
-                ID, USER, INSTALLER, null, extensionVersions);
+                ID, 567, USER, INSTALLER, null, extensionVersions);
 
         expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
         expectedRb.setRestoreUserDataInProgress(true);
@@ -315,7 +316,7 @@
     @Test
     public void saveAndDelete() {
         Rollback rollback = mRollbackStore.createNonStagedRollback(
-                ID, USER, INSTALLER, null, new SparseIntArray(0));
+                ID, 567, USER, INSTALLER, null, new SparseIntArray(0));
 
         RollbackStore.saveRollback(rollback);
 
@@ -331,7 +332,7 @@
     @Test
     public void saveToHistoryAndLoad() {
         Rollback origRb = mRollbackStore.createNonStagedRollback(
-                ID, USER, INSTALLER, null, new SparseIntArray(0));
+                ID, 567, USER, INSTALLER, null, new SparseIntArray(0));
         mRollbackStore.saveRollbackToHistory(origRb);
 
         List<Rollback> loadedRollbacks = mRollbackStore.loadHistorialRollbacks();
@@ -364,7 +365,7 @@
         assertThat(b.getApexPackageNames())
                 .containsExactlyElementsIn(a.getApexPackageNames());
 
-        assertThat(b.getStagedSessionId()).isEqualTo(a.getStagedSessionId());
+        assertThat(b.getOriginalSessionId()).isEqualTo(a.getOriginalSessionId());
 
         assertThat(b.info.getCommittedSessionId()).isEqualTo(a.info.getCommittedSessionId());
 
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index cf1ed48..5ba4851 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -74,18 +74,28 @@
         when(mMockPmi.getPackageList()).thenReturn(mPackageList);
     }
 
+    private Rollback createStagedRollback(int rollbackId, File backupDir, int originalSessionId) {
+        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ true, USER,
+                INSTALLER, null, new SparseIntArray(0));
+    }
+
+    private Rollback createNonStagedRollback(int rollbackId, File backupDir) {
+        return new Rollback(rollbackId, backupDir, -1, /* isStaged */ false, USER,
+                INSTALLER, null, new SparseIntArray(0));
+    }
+
     @Test
     public void newEmptyStagedRollbackDefaults() {
         int rollbackId = 123;
         int sessionId = 567;
         File file = new File("/test/testing");
 
-        Rollback rollback = new Rollback(rollbackId, file, sessionId, USER, INSTALLER);
+        Rollback rollback = createStagedRollback(rollbackId, file, sessionId);
 
         assertThat(rollback.isEnabling()).isTrue();
         assertThat(rollback.getBackupDir().getAbsolutePath()).isEqualTo("/test/testing");
         assertThat(rollback.isStaged()).isTrue();
-        assertThat(rollback.getStagedSessionId()).isEqualTo(567);
+        assertThat(rollback.getOriginalSessionId()).isEqualTo(567);
     }
 
     @Test
@@ -93,7 +103,7 @@
         int rollbackId = 123;
         File file = new File("/test/testing");
 
-        Rollback rollback = new Rollback(rollbackId, file, -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(rollbackId, file);
 
         assertThat(rollback.isEnabling()).isTrue();
         assertThat(rollback.getBackupDir().getAbsolutePath()).isEqualTo("/test/testing");
@@ -102,8 +112,7 @@
 
     @Test
     public void rollbackMadeAvailable() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER,
-                INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
 
         assertThat(rollback.isEnabling()).isTrue();
         assertThat(rollback.isAvailable()).isFalse();
@@ -121,7 +130,7 @@
 
     @Test
     public void deletedRollbackCannotBeMadeAvailable() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
 
         rollback.delete(mMockDataHelper, "test");
 
@@ -135,7 +144,7 @@
 
     @Test
     public void getPackageNamesAllAndJustApex() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 11, true);
         PackageRollbackInfo pkgInfo3 = newPkgInfoFor(PKG_3, 19, 1, false);
@@ -149,7 +158,7 @@
 
     @Test
     public void includesPackagesAfterEnable() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         PackageRollbackInfo pkgInfo3 = newPkgInfoFor(PKG_3, 157, 156, false);
@@ -177,7 +186,7 @@
 
     @Test
     public void snapshotWhenEnabling() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -195,7 +204,7 @@
 
     @Test
     public void snapshotWhenAvailable() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -216,7 +225,7 @@
 
     @Test
     public void snapshotWhenDeleted() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -237,7 +246,7 @@
 
     @Test
     public void snapshotThenDeleteNoApex() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, false);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -259,7 +268,7 @@
 
     @Test
     public void snapshotThenDeleteWithApex() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -282,7 +291,7 @@
 
     @Test
     public void restoreUserDataDoesNothingIfNotInProgress() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -297,7 +306,7 @@
 
     @Test
     public void restoreUserDataDoesNothingIfPackageNotFound() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -313,7 +322,7 @@
 
     @Test
     public void restoreUserDataRestoresIfInProgressAndPackageFound() {
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER);
+        Rollback rollback = createNonStagedRollback(123, new File("/test/testing"));
         PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
         PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
@@ -329,20 +338,9 @@
     }
 
     @Test
-    public void notifySessionWithSuccess() {
-        int[] sessionIds = new int[]{ 7777, 8888 };
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER,
-                sessionIds, new SparseIntArray(0));
-        // The 1st invocation returns false because not all child sessions are notified.
-        assertThat(rollback.notifySessionWithSuccess()).isFalse();
-        // The 2nd invocation returns true because now all child sessions are notified.
-        assertThat(rollback.notifySessionWithSuccess()).isTrue();
-    }
-
-    @Test
     public void allPackagesEnabled() {
         int[] sessionIds = new int[]{ 7777, 8888 };
-        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER,
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1, false, USER, INSTALLER,
                 sessionIds, new SparseIntArray(0));
         // #allPackagesEnabled returns false when 1 out of 2 packages is enabled.
         rollback.info.getPackages().add(newPkgInfoFor(PKG_1, 12, 10, false));
diff --git a/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java b/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java
index fa2123c..03ccf8c 100644
--- a/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/rotationresolver/RotationResolverManagerPerUserServiceTest.java
@@ -76,7 +76,8 @@
         // setup a spy for the RotationResolverManagerPerUserService.
         final RotationResolverManagerService mainService = new RotationResolverManagerService(
                 mContext);
-        mService = new RotationResolverManagerPerUserService(mainService, /* Lock */ new Object(),
+        final Object lock = new Object();
+        mService = new RotationResolverManagerPerUserService(mainService, lock,
                 mContext.getUserId());
 
         mCancellationSignal = new CancellationSignal();
@@ -84,15 +85,13 @@
         mRequest = new RotationResolutionRequest("", Surface.ROTATION_0, Surface.ROTATION_0,
                 true, 1000L);
         this.mService.mCurrentRequest = new RemoteRotationResolverService.RotationRequest(
-                mMockCallbackInternal, mRequest, mCancellationSignal);
+                mMockCallbackInternal, mRequest, mCancellationSignal, lock);
 
         this.mService.getMaster().mIsServiceEnabled = true;
 
         ComponentName componentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
         this.mService.mRemoteService = new MockRemoteRotationResolverService(mContext,
-                componentName, mContext.getUserId(),
-                /* idleUnbindTimeoutMs */60000L,
-                /* Lock */ new Object());
+                componentName, mContext.getUserId(), /* idleUnbindTimeoutMs */60000L);
     }
 
     @Test
@@ -126,13 +125,13 @@
     }
 
     static class MockRemoteRotationResolverService extends RemoteRotationResolverService {
-        MockRemoteRotationResolverService(Context context, ComponentName serviceName,
-                int userId, long idleUnbindTimeoutMs, Object lock) {
-            super(context, serviceName, userId, idleUnbindTimeoutMs, lock);
+        MockRemoteRotationResolverService(Context context, ComponentName serviceName, int userId,
+                long idleUnbindTimeoutMs) {
+            super(context, serviceName, userId, idleUnbindTimeoutMs);
         }
 
         @Override
-        public void resolveRotationLocked(RotationRequest request) {
+        public void resolveRotation(RotationRequest request) {
             request.mCallbackInternal.onSuccess(request.mRemoteRequest.getProposedRotation());
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
new file mode 100644
index 0000000..1947481
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+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.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.Status;
+import android.os.HwParcel;
+import android.os.IBinder;
+import android.os.IHwBinder;
+import android.os.IHwInterface;
+import android.os.RemoteException;
+import android.system.OsConstants;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.ArgumentCaptor;
+
+import java.util.LinkedList;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public class SoundHw2CompatTest {
+    @Parameterized.Parameter(0) public String mVersion;
+    @Parameterized.Parameter(1) public boolean mSupportConcurrentCapture;
+
+    private final Runnable mRebootRunnable = mock(Runnable.class);
+    private ISoundTriggerHal mCanonical;
+    private CaptureStateNotifier mCaptureStateNotifier;
+    private android.hardware.soundtrigger.V2_0.ISoundTriggerHw mHalDriver;
+
+    // We run the test once for every version of the underlying driver.
+    @Parameterized.Parameters(name = "{0}, concurrent={1}")
+    public static Iterable<Object[]> data() {
+        List<Object[]> result = new LinkedList<>();
+
+        for (String version : new String[]{"V2_0", "V2_1", "V2_2", "V2_3", "V2_4",}) {
+            for (boolean concurrentCapture : new boolean[]{false, true}) {
+                result.add(new Object[]{version, concurrentCapture});
+            }
+        }
+
+        return result;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mHalDriver = (android.hardware.soundtrigger.V2_0.ISoundTriggerHw) mock(Class.forName(
+                String.format("android.hardware.soundtrigger.%s.ISoundTriggerHw", mVersion)));
+
+        clearInvocations(mRebootRunnable);
+
+        // This binder is associated with the mock, so it can be cast to either version of the
+        // HAL interface.
+        final IHwBinder binder = new IHwBinder() {
+            @Override
+            public void transact(int code, HwParcel request, HwParcel reply, int flags)
+                    throws RemoteException {
+                // This is a little hacky, but a very easy way to gracefully reject a request for
+                // an unsupported interface (after queryLocalInterface() returns null, the client
+                // will attempt a remote transaction to obtain the interface. RemoteException will
+                // cause it to give up).
+                throw new RemoteException();
+            }
+
+            @Override
+            public IHwInterface queryLocalInterface(String descriptor) {
+                if (descriptor.equals("android.hardware.soundtrigger@2.0::ISoundTriggerHw")
+                        || descriptor.equals("android.hardware.soundtrigger@2.1::ISoundTriggerHw")
+                        && mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw
+                        || descriptor.equals("android.hardware.soundtrigger@2.2::ISoundTriggerHw")
+                        && mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw
+                        || descriptor.equals("android.hardware.soundtrigger@2.3::ISoundTriggerHw")
+                        && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw
+                        || descriptor.equals("android.hardware.soundtrigger@2.4::ISoundTriggerHw")
+                        && mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+                    return mHalDriver;
+                }
+                return null;
+            }
+
+            @Override
+            public boolean linkToDeath(DeathRecipient recipient, long cookie) {
+                try {
+                    return mHalDriver.linkToDeath(recipient, cookie);
+                } catch (RemoteException e) {
+                    throw e.rethrowAsRuntimeException();
+                }
+            }
+
+            @Override
+            public boolean unlinkToDeath(DeathRecipient recipient) {
+                try {
+                    return mHalDriver.unlinkToDeath(recipient);
+                } catch (RemoteException e) {
+                    throw e.rethrowAsRuntimeException();
+                }
+            }
+        };
+        when(mHalDriver.asBinder()).thenReturn(binder);
+
+        android.hardware.soundtrigger.V2_3.Properties halProperties =
+                TestUtil.createDefaultProperties_2_3(mSupportConcurrentCapture);
+        doAnswer(invocation -> {
+            ((android.hardware.soundtrigger.V2_0.ISoundTriggerHw.getPropertiesCallback) invocation.getArgument(
+                    0)).onValues(0, halProperties.base);
+            return null;
+        }).when(mHalDriver).getProperties(any());
+
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
+            android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
+                    (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+            doAnswer(invocation -> {
+                ((android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getProperties_2_3Callback) invocation.getArgument(
+                        0)).onValues(0, halProperties);
+                return null;
+            }).when(driver).getProperties_2_3(any());
+        }
+
+        mCaptureStateNotifier = spy(new CaptureStateNotifier());
+
+        mCanonical = SoundTriggerHw2Compat.create(mHalDriver, mRebootRunnable,
+                mCaptureStateNotifier);
+
+        // During initialization any method can be called, but after we're starting to enforce that
+        // no additional methods are called.
+        clearInvocations(mHalDriver);
+    }
+
+    @After
+    public void tearDown() {
+        mCanonical.detach();
+        verifyNoMoreInteractions(mHalDriver);
+        verifyNoMoreInteractions(mRebootRunnable);
+        mCaptureStateNotifier.verifyNoMoreListeners();
+    }
+
+    @Test
+    public void testSetUpAndTearDown() {
+    }
+
+    @Test
+    public void testReboot() {
+        mCanonical.reboot();
+        verify(mRebootRunnable).run();
+    }
+
+    @Test
+    public void testGetProperties() throws Exception {
+        Properties properties = mCanonical.getProperties();
+
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
+            android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
+                    (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+            // It is OK for the SUT to cache the properties, so the underlying method doesn't
+            // need to be called every single time.
+            verify(driver, atMost(1)).getProperties_2_3(any());
+            TestUtil.validateDefaultProperties(properties, mSupportConcurrentCapture);
+        } else {
+            // It is OK for the SUT to cache the properties, so the underlying method doesn't
+            // need to be called every single time.
+            verify(mHalDriver, atMost(1)).getProperties(any());
+            TestUtil.validateDefaultProperties(properties, mSupportConcurrentCapture, 0, "");
+        }
+    }
+
+    private int loadGenericModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final int handle = 29;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel> modelCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class);
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadSoundModelCallback
+                    resultCallback = invocation.getArgument(3);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, handle);
+            return null;
+        }).when(mHalDriver).loadSoundModel(any(), any(), anyInt(), any());
+
+        assertEquals(handle,
+                mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback));
+
+        verify(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture(), anyInt(),
+                any());
+
+        TestUtil.validateGenericSoundModel_2_0(modelCaptor.getValue());
+        validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback);
+        return handle;
+    }
+
+    private int loadGenericModel_2_1(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 =
+                (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
+
+        final int handle = 29;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback
+                    resultCallback = invocation.getArgument(3);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, handle);
+            return null;
+        }).when(driver_2_1).loadSoundModel_2_1(any(), any(), anyInt(), any());
+
+        assertEquals(handle,
+                mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback));
+
+        verify(driver_2_1).loadSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
+                anyInt(), any());
+
+        TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue());
+        validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
+        return handle;
+    }
+
+    private int loadGenericModel_2_4(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+
+        final int handle = 29;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.class);
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadSoundModel_2_4Callback
+                    resultCallback = invocation.getArgument(2);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, handle);
+            return null;
+        }).when(driver_2_4).loadSoundModel_2_4(any(), any(), any());
+
+        assertEquals(handle,
+                mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback));
+
+        verify(driver_2_4).loadSoundModel_2_4(modelCaptor.capture(), callbackCaptor.capture(),
+                any());
+
+        TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue());
+        validateCallback_2_4(callbackCaptor.getValue(), canonicalCallback);
+        return handle;
+    }
+
+    private int loadGenericModel(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            return loadGenericModel_2_4(canonicalCallback);
+        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
+            return loadGenericModel_2_1(canonicalCallback);
+        } else {
+            return loadGenericModel_2_0(canonicalCallback);
+        }
+    }
+
+    @Test
+    public void testLoadGenericModel() throws Exception {
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        loadGenericModel(canonicalCallback);
+    }
+
+    @Test
+    public void testMaxModels() throws Exception {
+        assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw);
+
+        // Register global callback.
+        ISoundTriggerHal.GlobalCallback globalCallback = mock(
+                ISoundTriggerHal.GlobalCallback.class);
+        mCanonical.registerCallback(globalCallback);
+
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        final int maxModels = TestUtil.createDefaultProperties_2_0(false).maxSoundModels;
+        int[] modelHandles = new int[maxModels];
+
+        // Load as many models as we're allowed.
+        for (int i = 0; i < maxModels; ++i) {
+            modelHandles[i] = loadGenericModel(canonicalCallback);
+            verifyNoMoreInteractions(mHalDriver);
+            clearInvocations(mHalDriver);
+        }
+
+        // Now try to load an additional one and expect failure without invoking the underlying
+        // driver.
+        try {
+            mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(), canonicalCallback);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
+        }
+
+        // Unload a single model and expect a onResourcesAvailable().
+        mCanonical.unloadSoundModel(modelHandles[0]);
+        verify(mHalDriver).unloadSoundModel(modelHandles[0]);
+
+        mCanonical.flushCallbacks();
+        verify(globalCallback).onResourcesAvailable();
+    }
+
+    private void testLoadGenericModelBusy_2_4() throws Exception {
+        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadSoundModel_2_4Callback
+                    resultCallback = invocation.getArgument(2);
+
+            // This is the return of this method.
+            resultCallback.onValues(-OsConstants.EBUSY, 0);
+            return null;
+        }).when(driver_2_4).loadSoundModel_2_4(any(), any(), any());
+
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        try {
+            mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
+        }
+        verify(driver_2_4).loadSoundModel_2_4(any(), any(), any());
+    }
+
+    @Test
+    public void testLoadGenericModelBusy() throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            testLoadGenericModelBusy_2_4();
+        }
+    }
+
+    private int loadPhraseModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final int handle = 29;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel>
+                modelCaptor = ArgumentCaptor.forClass(
+                android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class);
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadPhraseSoundModelCallback
+                    resultCallback = invocation.getArgument(3);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, handle);
+            return null;
+        }).when(mHalDriver).loadPhraseSoundModel(any(), any(), anyInt(), any());
+
+        assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(),
+                canonicalCallback));
+
+        verify(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture(),
+                anyInt(), any());
+
+        TestUtil.validatePhraseSoundModel_2_0(modelCaptor.getValue());
+        validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback);
+        return handle;
+    }
+
+    private int loadPhraseModel_2_1(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 =
+                (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
+
+        final int handle = 29;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel>
+                modelCaptor = ArgumentCaptor.forClass(
+                android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback
+                    resultCallback = invocation.getArgument(3);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, handle);
+            return null;
+        }).when(driver_2_1).loadPhraseSoundModel_2_1(any(), any(), anyInt(), any());
+
+        assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(),
+                canonicalCallback));
+
+        verify(driver_2_1).loadPhraseSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
+                anyInt(), any());
+
+        TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue());
+        validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
+        return handle;
+    }
+
+    private int loadPhraseModel_2_4(ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+
+        final int handle = 29;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel>
+                modelCaptor = ArgumentCaptor.forClass(
+                android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.class);
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadPhraseSoundModel_2_4Callback
+                    resultCallback = invocation.getArgument(2);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, handle);
+            return null;
+        }).when(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any());
+
+        assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(),
+                canonicalCallback));
+
+        verify(driver_2_4).loadPhraseSoundModel_2_4(modelCaptor.capture(), callbackCaptor.capture(),
+                any());
+
+        TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue());
+        validateCallback_2_4(callbackCaptor.getValue(), canonicalCallback);
+        return handle;
+    }
+
+    public int loadPhraseModel(ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            return loadPhraseModel_2_4(canonicalCallback);
+        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
+            return loadPhraseModel_2_1(canonicalCallback);
+        } else {
+            return loadPhraseModel_2_0(canonicalCallback);
+        }
+    }
+
+    @Test
+    public void testLoadPhraseModel() throws Exception {
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        loadPhraseModel(canonicalCallback);
+    }
+
+    private void testLoadPhraseModelBusy_2_4() throws Exception {
+        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadPhraseSoundModel_2_4Callback
+                    resultCallback = invocation.getArgument(2);
+
+            // This is the return of this method.
+            resultCallback.onValues(-OsConstants.EBUSY, 0);
+            return null;
+        }).when(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any());
+
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        try {
+            mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(), canonicalCallback);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
+        }
+        verify(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any());
+    }
+
+    @Test
+    public void testLoadPhraseModelBusy() throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            testLoadPhraseModelBusy_2_4();
+        }
+    }
+
+    @Test
+    public void testUnloadModel() throws Exception {
+        mCanonical.unloadSoundModel(14);
+        verify(mHalDriver).unloadSoundModel(14);
+    }
+
+    private void startRecognition_2_0(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig>
+                configCaptor = ArgumentCaptor.forClass(
+                android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class);
+
+        when(mHalDriver.startRecognition(eq(handle), any(), any(), anyInt())).thenReturn(0);
+
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
+        mCanonical.startRecognition(handle, 203, 204, config);
+        verify(mHalDriver).startRecognition(eq(handle), configCaptor.capture(),
+                callbackCaptor.capture(), anyInt());
+
+        TestUtil.validateRecognitionConfig_2_0(configCaptor.getValue(), 203, 204);
+        validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback);
+    }
+
+    private void startRecognition_2_1(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 =
+                (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
+
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig>
+                configCaptor = ArgumentCaptor.forClass(
+                android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig.class);
+        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
+
+        when(driver_2_1.startRecognition_2_1(eq(handle), any(), any(), anyInt())).thenReturn(0);
+
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
+        mCanonical.startRecognition(handle, 505, 506, config);
+        verify(driver_2_1).startRecognition_2_1(eq(handle), configCaptor.capture(),
+                callbackCaptor.capture(), anyInt());
+
+        TestUtil.validateRecognitionConfig_2_1(configCaptor.getValue(), 505, 506);
+        validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
+    }
+
+    private void startRecognition_2_3(int handle) throws Exception {
+        final android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 =
+                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> configCaptor =
+                ArgumentCaptor.forClass(android.hardware.soundtrigger.V2_3.RecognitionConfig.class);
+
+        when(driver_2_3.startRecognition_2_3(eq(handle), any())).thenReturn(0);
+
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
+        mCanonical.startRecognition(handle, 808, 909, config);
+        verify(driver_2_3).startRecognition_2_3(eq(handle), configCaptor.capture());
+        TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 808, 909);
+    }
+
+    private void startRecognition_2_4(int handle) throws Exception {
+        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+        ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> configCaptor =
+                ArgumentCaptor.forClass(android.hardware.soundtrigger.V2_3.RecognitionConfig.class);
+
+        when(driver_2_4.startRecognition_2_4(eq(handle), any())).thenReturn(0);
+
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
+        mCanonical.startRecognition(handle, 21, 22, config);
+        verify(driver_2_4).startRecognition_2_4(eq(handle), configCaptor.capture());
+        TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 21, 22);
+    }
+
+    private void startRecognition(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)
+            throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            startRecognition_2_4(handle);
+        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
+            startRecognition_2_3(handle);
+        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
+            startRecognition_2_1(handle, canonicalCallback);
+        } else {
+            startRecognition_2_0(handle, canonicalCallback);
+        }
+    }
+
+    @Test
+    public void testStartRecognition() throws Exception {
+        // First load.
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        final int handle = loadGenericModel(canonicalCallback);
+
+        // Then start.
+        startRecognition(handle, canonicalCallback);
+    }
+
+    private void testStartRecognitionBusy_2_4() throws Exception {
+        final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+
+        final int handle = 68;
+        when(driver_2_4.startRecognition_2_4(eq(handle), any())).thenReturn(-OsConstants.EBUSY);
+
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
+        try {
+            mCanonical.startRecognition(handle, 34, 35, config);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
+        }
+        verify(driver_2_4).startRecognition_2_4(eq(handle), any());
+    }
+
+    @Test
+    public void testStartRecognitionBusy() throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            testStartRecognitionBusy_2_4();
+        }
+    }
+
+    @Test
+    public void testNoRegisterCaptureStateListener() {
+        assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw
+                || mSupportConcurrentCapture);
+        verify(mCaptureStateNotifier, never()).registerListener(any());
+    }
+
+    @Test
+    public void testConcurrentCaptureAbort() throws Exception {
+        assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw
+                || mSupportConcurrentCapture);
+        verify(mCaptureStateNotifier, atLeast(1)).registerListener(any());
+
+        // Register global callback.
+        ISoundTriggerHal.GlobalCallback globalCallback = mock(
+                ISoundTriggerHal.GlobalCallback.class);
+        mCanonical.registerCallback(globalCallback);
+
+        // Load.
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        final int handle = loadGenericModel(canonicalCallback);
+
+        // Then start.
+        startRecognition(handle, canonicalCallback);
+
+        // Now activate external capture.
+        mCaptureStateNotifier.setState(true);
+
+        // Expect hardware to have been stopped.
+        verify(mHalDriver).stopRecognition(handle);
+
+        // Expect an abort event (async).
+        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEvent.class);
+        mCanonical.flushCallbacks();
+        verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
+        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+
+        // Deactivate external capture.
+        mCaptureStateNotifier.setState(false);
+
+        // Expect a onResourcesAvailable().
+        mCanonical.flushCallbacks();
+        verify(globalCallback).onResourcesAvailable();
+    }
+
+    @Test
+    public void testConcurrentCaptureReject() throws Exception {
+        assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw
+                || mSupportConcurrentCapture);
+        verify(mCaptureStateNotifier, atLeast(1)).registerListener(any());
+
+        // Register global callback.
+        ISoundTriggerHal.GlobalCallback globalCallback = mock(
+                ISoundTriggerHal.GlobalCallback.class);
+        mCanonical.registerCallback(globalCallback);
+
+        // Load (this registers the callback).
+        ISoundTriggerHal.ModelCallback canonicalCallback = mock(
+                ISoundTriggerHal.ModelCallback.class);
+        final int handle = loadGenericModel(canonicalCallback);
+
+        // Report external capture active.
+        mCaptureStateNotifier.setState(true);
+
+        // Then start.
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
+        try {
+            mCanonical.startRecognition(handle, 203, 204, config);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
+        }
+
+        // Deactivate external capture.
+        mCaptureStateNotifier.setState(false);
+
+        // Expect a onResourcesAvailable().
+        mCanonical.flushCallbacks();
+        verify(globalCallback).onResourcesAvailable();
+    }
+
+    @Test
+    public void testStopRecognition() throws Exception {
+        mCanonical.stopRecognition(17);
+        verify(mHalDriver).stopRecognition(17);
+    }
+
+    @Test
+    public void testForceRecognition() throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw) {
+            android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver_2_2 =
+                    (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver;
+            mCanonical.forceRecognitionEvent(14);
+            verify(driver_2_2).getModelState(14);
+        } else {
+            try {
+                mCanonical.forceRecognitionEvent(14);
+                fail("Expected an exception");
+            } catch (RecoverableException e) {
+                assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode);
+            }
+        }
+    }
+
+    @Test
+    public void testGetParameter() throws Exception {
+        assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw);
+
+        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 =
+                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getParameterCallback resultCallback =
+                    invocation.getArgument(2);
+
+            // This is the return of this method.
+            resultCallback.onValues(0, 99);
+            return null;
+        }).when(driver_2_3).getParameter(eq(21), eq(47), any());
+
+        assertEquals(99, mCanonical.getModelParameter(21, 47));
+        verify(driver_2_3).getParameter(eq(21), eq(47), any());
+    }
+
+    @Test
+    public void testSetParameter() throws Exception {
+        assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw);
+
+        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 =
+                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+
+        mCanonical.setModelParameter(212, 247, 80);
+        verify(driver_2_3).setParameter(212, 247, 80);
+    }
+
+    @Test
+    public void testQueryParameterSupported() throws Exception {
+        assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw);
+
+        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 =
+                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+
+        doAnswer(invocation -> {
+            android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback
+                    resultCallback = invocation.getArgument(2);
+
+            // This is the return of this method.
+            android.hardware.soundtrigger.V2_3.ModelParameterRange range =
+                    new android.hardware.soundtrigger.V2_3.ModelParameterRange();
+            range.start = 34;
+            range.end = 45;
+            android.hardware.soundtrigger.V2_3.OptionalModelParameterRange optionalRange =
+                    new android.hardware.soundtrigger.V2_3.OptionalModelParameterRange();
+            optionalRange.range(range);
+            resultCallback.onValues(0, optionalRange);
+            return null;
+        }).when(driver_2_3).queryParameter(eq(11), eq(12), any());
+
+        ModelParameterRange range = mCanonical.queryParameter(11, 12);
+        assertNotNull(range);
+        assertEquals(34, range.minInclusive);
+        assertEquals(45, range.maxInclusive);
+        verify(driver_2_3).queryParameter(eq(11), eq(12), any());
+    }
+
+    @Test
+    public void testQueryParameterNotSupported() throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
+            android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 =
+                    (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
+
+            doAnswer(invocation -> {
+                android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback
+                        resultCallback = invocation.getArgument(2);
+
+                // This is the return of this method.
+                android.hardware.soundtrigger.V2_3.OptionalModelParameterRange optionalRange =
+                        new android.hardware.soundtrigger.V2_3.OptionalModelParameterRange();
+                resultCallback.onValues(0, optionalRange);
+                return null;
+            }).when(driver_2_3).queryParameter(eq(11), eq(12), any());
+
+            ModelParameterRange range = mCanonical.queryParameter(11, 12);
+            assertNull(range);
+            verify(driver_2_3).queryParameter(eq(11), eq(12), any());
+        } else {
+            ModelParameterRange range = mCanonical.queryParameter(11, 12);
+            assertNull(range);
+        }
+    }
+
+    private void testGlobalCallback_2_0() {
+        ISoundTriggerHal.GlobalCallback canonicalCallback = mock(
+                ISoundTriggerHal.GlobalCallback.class);
+        mCanonical.registerCallback(canonicalCallback);
+        // We just care that it doesn't throw.
+    }
+
+    private void testGlobalCallback_2_4() throws Exception {
+        android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 =
+                (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver;
+
+        ISoundTriggerHal.GlobalCallback canonicalCallback = mock(
+                ISoundTriggerHal.GlobalCallback.class);
+        mCanonical.registerCallback(canonicalCallback);
+
+        ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback>
+                callbackCaptor = ArgumentCaptor.forClass(
+                android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback.class);
+        verify(driver_2_4).registerGlobalCallback(callbackCaptor.capture());
+        validateGlobalCallback_2_4(callbackCaptor.getValue(), canonicalCallback);
+    }
+
+    @Test
+    public void testGlobalCallback() throws Exception {
+        if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) {
+            testGlobalCallback_2_4();
+        } else {
+            testGlobalCallback_2_0();
+        }
+    }
+
+    @Test
+    public void testLinkToDeath() throws Exception {
+        IBinder.DeathRecipient canonicalRecipient = mock(IBinder.DeathRecipient.class);
+        when(mHalDriver.linkToDeath(any(), anyLong())).thenReturn(true);
+        mCanonical.linkToDeath(canonicalRecipient);
+
+        ArgumentCaptor<IHwBinder.DeathRecipient> recipientCaptor = ArgumentCaptor.forClass(
+                IHwBinder.DeathRecipient.class);
+        ArgumentCaptor<Long> cookieCaptor = ArgumentCaptor.forClass(Long.class);
+        verify(mHalDriver).linkToDeath(recipientCaptor.capture(), cookieCaptor.capture());
+
+        recipientCaptor.getValue().serviceDied(cookieCaptor.getValue());
+        mCanonical.flushCallbacks();
+        verify(canonicalRecipient).binderDied();
+
+        mCanonical.unlinkToDeath(canonicalRecipient);
+        verify(mHalDriver).unlinkToDeath(recipientCaptor.getValue());
+    }
+
+    @Test
+    public void testInterfaceDescriptor() throws Exception {
+        when(mHalDriver.interfaceDescriptor()).thenReturn("ABCD");
+        assertEquals("ABCD", mCanonical.interfaceDescriptor());
+        verify(mHalDriver).interfaceDescriptor();
+    }
+
+    private void validateGlobalCallback_2_4(
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback hwCallback,
+            ISoundTriggerHal.GlobalCallback canonicalCallback) throws Exception {
+        hwCallback.onResourcesAvailable();
+        mCanonical.flushCallbacks();
+        verify(canonicalCallback).onResourcesAvailable();
+    }
+
+    private void validateCallback_2_0(
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback hwCallback,
+            ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
+        {
+            final int handle = 85;
+            final int status =
+                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
+            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEvent.class);
+
+            hwCallback.recognitionCallback(TestUtil.createRecognitionEvent_2_0(handle, status), 99);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
+            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED);
+        }
+
+        {
+            final int handle = 92;
+            final int status =
+                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
+            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                    PhraseRecognitionEvent.class);
+
+            hwCallback.phraseRecognitionCallback(
+                    TestUtil.createPhraseRecognitionEvent_2_0(handle, status), 99);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
+            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+                    RecognitionStatus.SUCCESS);
+        }
+        verifyNoMoreInteractions(canonicalCallback);
+        clearInvocations(canonicalCallback);
+    }
+
+    private void validateCallback_2_1(
+            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback hwCallback,
+            ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
+        {
+            final int handle = 85;
+            final int status =
+                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
+            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEvent.class);
+
+            hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
+                    99);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
+            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED);
+        }
+
+        {
+            final int handle = 92;
+            final int status =
+                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
+            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                    PhraseRecognitionEvent.class);
+
+            hwCallback.phraseRecognitionCallback_2_1(
+                    TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
+            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+                    RecognitionStatus.SUCCESS);
+        }
+        verifyNoMoreInteractions(canonicalCallback);
+        clearInvocations(canonicalCallback);
+    }
+
+    private void validateCallback_2_4(
+            android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback hwCallback,
+            ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception {
+        {
+            final int handle = 85;
+            final int status =
+                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
+            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEvent.class);
+
+            hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
+                    99);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
+            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED);
+        }
+
+        {
+            final int handle = 92;
+            final int status =
+                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
+            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+                    PhraseRecognitionEvent.class);
+
+            hwCallback.phraseRecognitionCallback_2_1(
+                    TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
+            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+                    RecognitionStatus.SUCCESS);
+        }
+
+        {
+            final int handle = 23;
+            hwCallback.modelUnloaded(handle);
+            mCanonical.flushCallbacks();
+            verify(canonicalCallback).modelUnloaded(handle);
+        }
+        verifyNoMoreInteractions(canonicalCallback);
+        clearInvocations(canonicalCallback);
+    }
+
+    public static class CaptureStateNotifier implements ICaptureStateNotifier {
+        private final List<Listener> mListeners = new LinkedList<>();
+
+        @Override
+        public boolean registerListener(Listener listener) {
+            mListeners.add(listener);
+            return false;
+        }
+
+        @Override
+        public void unregisterListener(Listener listener) {
+            mListeners.remove(listener);
+        }
+
+        public void setState(boolean state) {
+            for (Listener listener : mListeners) {
+                listener.onCaptureStateChange(state);
+            }
+        }
+
+        public void verifyNoMoreListeners() {
+            assertEquals(0, mListeners.size());
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 509eb25..1daf831 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -16,89 +16,50 @@
 
 package com.android.server.soundtrigger_middleware;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 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.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.hardware.audio.common.V2_0.AudioConfig;
-import android.hardware.audio.common.V2_0.Uuid;
-import android.hardware.soundtrigger.V2_3.OptionalModelParameterRange;
-import android.media.audio.common.AudioChannelMask;
-import android.media.audio.common.AudioFormat;
-import android.media.soundtrigger_middleware.AudioCapabilities;
-import android.media.soundtrigger_middleware.ConfidenceLevel;
+import android.media.soundtrigger.ModelParameter;
+import android.media.soundtrigger.ModelParameterRange;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
-import android.media.soundtrigger_middleware.ModelParameter;
-import android.media.soundtrigger_middleware.ModelParameterRange;
-import android.media.soundtrigger_middleware.Phrase;
-import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
-import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
-import android.media.soundtrigger_middleware.PhraseSoundModel;
-import android.media.soundtrigger_middleware.RecognitionConfig;
-import android.media.soundtrigger_middleware.RecognitionEvent;
-import android.media.soundtrigger_middleware.RecognitionMode;
-import android.media.soundtrigger_middleware.RecognitionStatus;
-import android.media.soundtrigger_middleware.SoundModel;
-import android.media.soundtrigger_middleware.SoundModelType;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
-import android.os.HidlMemoryUtil;
-import android.os.HwParcel;
-import android.os.IHwBinder;
-import android.os.IHwInterface;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.SharedMemory;
-import android.system.ErrnoException;
 import android.util.Pair;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.runners.JUnit4;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.stubbing.Answer;
 
-import java.io.FileDescriptor;
-import java.nio.ByteBuffer;
-
-@RunWith(Parameterized.class)
+@RunWith(JUnit4.class)
 public class SoundTriggerMiddlewareImplTest {
-    private static final String TAG = "SoundTriggerMiddlewareImplTest";
+    @Mock public ISoundTriggerHal mHalDriver = mock(ISoundTriggerHal.class);
 
-    // We run the test once for every version of the underlying driver.
-    @Parameterized.Parameters
-    public static Object[] data() {
-        return new Object[]{
-                mock(android.hardware.soundtrigger.V2_0.ISoundTriggerHw.class),
-                mock(android.hardware.soundtrigger.V2_1.ISoundTriggerHw.class),
-                mock(android.hardware.soundtrigger.V2_2.ISoundTriggerHw.class),
-                mock(android.hardware.soundtrigger.V2_3.ISoundTriggerHw.class),
-        };
-    }
-
-    @Mock
-    @Parameterized.Parameter
-    public android.hardware.soundtrigger.V2_0.ISoundTriggerHw mHalDriver;
-
-    @Mock
-    private SoundTriggerMiddlewareImpl.AudioSessionProvider mAudioSessionProvider = mock(
-            SoundTriggerMiddlewareImpl.AudioSessionProvider.class);
+    @Mock private final SoundTriggerMiddlewareImpl.AudioSessionProvider mAudioSessionProvider =
+            mock(SoundTriggerMiddlewareImpl.AudioSessionProvider.class);
 
     private SoundTriggerMiddlewareImpl mService;
 
@@ -106,522 +67,41 @@
         return mock(ISoundTriggerCallback.Stub.class, Mockito.CALLS_REAL_METHODS);
     }
 
-    private static SoundModel createGenericSoundModel() {
-        return createSoundModel(SoundModelType.GENERIC);
-    }
-
-    private static FileDescriptor byteArrayToFileDescriptor(byte[] data) {
-        try {
-            SharedMemory shmem = SharedMemory.create("", data.length);
-            ByteBuffer buffer = shmem.mapReadWrite();
-            buffer.put(data);
-            return shmem.getFileDescriptor();
-        } catch (ErrnoException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private static SoundModel createSoundModel(int type) {
-        SoundModel model = new SoundModel();
-        model.type = type;
-        model.uuid = "12345678-2345-3456-4567-abcdef987654";
-        model.vendorUuid = "87654321-5432-6543-7654-456789fedcba";
-        byte[] data = new byte[]{91, 92, 93, 94, 95};
-        model.data = new ParcelFileDescriptor(byteArrayToFileDescriptor(data));
-        model.dataSize = data.length;
-        return model;
-    }
-
-    private static PhraseSoundModel createPhraseSoundModel() {
-        PhraseSoundModel model = new PhraseSoundModel();
-        model.common = createSoundModel(SoundModelType.KEYPHRASE);
-        model.phrases = new Phrase[1];
-        model.phrases[0] = new Phrase();
-        model.phrases[0].id = 123;
-        model.phrases[0].users = new int[]{5, 6, 7};
-        model.phrases[0].locale = "locale";
-        model.phrases[0].text = "text";
-        model.phrases[0].recognitionModes =
-                RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION;
-        return model;
-    }
-
-    private static android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties createDefaultProperties(
-            boolean supportConcurrentCapture) {
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties properties =
-                new android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties();
-        properties.implementor = "implementor";
-        properties.description = "description";
-        properties.version = 123;
-        properties.uuid = new Uuid();
-        properties.uuid.timeLow = 1;
-        properties.uuid.timeMid = 2;
-        properties.uuid.versionAndTimeHigh = 3;
-        properties.uuid.variantAndClockSeqHigh = 4;
-        properties.uuid.node = new byte[]{5, 6, 7, 8, 9, 10};
-
-        properties.maxSoundModels = 456;
-        properties.maxKeyPhrases = 567;
-        properties.maxUsers = 678;
-        properties.recognitionModes =
-                android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER
-                | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION
-                | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION
-                | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER;
-        properties.captureTransition = true;
-        properties.maxBufferMs = 321;
-        properties.concurrentCapture = supportConcurrentCapture;
-        properties.triggerInEvent = true;
-        properties.powerConsumptionMw = 432;
-        return properties;
-    }
-
-    private static android.hardware.soundtrigger.V2_3.Properties createDefaultProperties_2_3(
-            boolean supportConcurrentCapture) {
-        android.hardware.soundtrigger.V2_3.Properties properties =
-                new android.hardware.soundtrigger.V2_3.Properties();
-        properties.base = createDefaultProperties(supportConcurrentCapture);
-        properties.supportedModelArch = "supportedModelArch";
-        properties.audioCapabilities =
-                android.hardware.soundtrigger.V2_3.AudioCapabilities.ECHO_CANCELLATION
-                        | android.hardware.soundtrigger.V2_3.AudioCapabilities.NOISE_SUPPRESSION;
-        return properties;
-    }
-
-    private void validateDefaultProperties(SoundTriggerModuleProperties properties,
-            boolean supportConcurrentCapture) {
-        assertEquals("implementor", properties.implementor);
-        assertEquals("description", properties.description);
-        assertEquals(123, properties.version);
-        assertEquals("00000001-0002-0003-0004-05060708090a", properties.uuid);
-        assertEquals(456, properties.maxSoundModels);
-        assertEquals(567, properties.maxKeyPhrases);
-        assertEquals(678, properties.maxUsers);
-        assertEquals(RecognitionMode.GENERIC_TRIGGER
-                | RecognitionMode.USER_AUTHENTICATION
-                | RecognitionMode.USER_IDENTIFICATION
-                | RecognitionMode.VOICE_TRIGGER, properties.recognitionModes);
-        assertTrue(properties.captureTransition);
-        assertEquals(321, properties.maxBufferMs);
-        assertEquals(supportConcurrentCapture, properties.concurrentCapture);
-        assertTrue(properties.triggerInEvent);
-        assertEquals(432, properties.powerConsumptionMw);
-
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-            assertEquals("supportedModelArch", properties.supportedModelArch);
-            assertEquals(AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION,
-                    properties.audioCapabilities);
-        } else {
-            assertEquals("", properties.supportedModelArch);
-            assertEquals(0, properties.audioCapabilities);
-        }
-    }
-
-    private void verifyNotGetProperties() throws RemoteException {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-            verify((android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver,
-                    never()).getProperties(any());
-        }
-    }
-
-    private static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_0(
-            int hwHandle,
-            int status) {
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent halEvent =
-                new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent();
-        halEvent.status = status;
-        halEvent.type = SoundModelType.GENERIC;
-        halEvent.model = hwHandle;
-        halEvent.captureAvailable = true;
-        // This field is ignored.
-        halEvent.captureSession = 123;
-        halEvent.captureDelayMs = 234;
-        halEvent.capturePreambleMs = 345;
-        halEvent.triggerInData = true;
-        halEvent.audioConfig = new AudioConfig();
-        halEvent.audioConfig.sampleRateHz = 456;
-        halEvent.audioConfig.channelMask = AudioChannelMask.IN_LEFT;
-        halEvent.audioConfig.format = AudioFormat.MP3;
-        // hwEvent.audioConfig.offloadInfo is irrelevant.
-        halEvent.data.add((byte) 31);
-        halEvent.data.add((byte) 32);
-        halEvent.data.add((byte) 33);
-        return halEvent;
-    }
-
-    private static android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1(
-            int hwHandle,
-            int status) {
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent halEvent =
-                new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent();
-        halEvent.header = createRecognitionEvent_2_0(hwHandle, status);
-        halEvent.header.data.clear();
-        halEvent.data = HidlMemoryUtil.byteArrayToHidlMemory(new byte[]{31, 32, 33});
-        return halEvent;
-    }
-
-    private static void validateRecognitionEvent(RecognitionEvent event, int status) {
-        assertEquals(status, event.status);
-        assertEquals(SoundModelType.GENERIC, event.type);
-        assertTrue(event.captureAvailable);
-        assertEquals(101, event.captureSession);
-        assertEquals(234, event.captureDelayMs);
-        assertEquals(345, event.capturePreambleMs);
-        assertTrue(event.triggerInData);
-        assertEquals(456, event.audioConfig.sampleRateHz);
-        assertEquals(AudioChannelMask.IN_LEFT, event.audioConfig.channelMask);
-        assertEquals(AudioFormat.MP3, event.audioConfig.format);
-    }
-
-    private static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_0(
-            int hwHandle, int status) {
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent =
-                new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent();
-        halEvent.common = createRecognitionEvent_2_0(hwHandle, status);
-
-        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra =
-                new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra();
-        halExtra.id = 123;
-        halExtra.confidenceLevel = 52;
-        halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER
-                | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER;
-        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel =
-                new android.hardware.soundtrigger.V2_0.ConfidenceLevel();
-        halLevel.userId = 31;
-        halLevel.levelPercent = 43;
-        halExtra.levels.add(halLevel);
-        halEvent.phraseExtras.add(halExtra);
-        return halEvent;
-    }
-
-    private static android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_1(
-            int hwHandle, int status) {
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent =
-                new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent();
-        halEvent.common = createRecognitionEvent_2_1(hwHandle, status);
-
-        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra =
-                new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra();
-        halExtra.id = 123;
-        halExtra.confidenceLevel = 52;
-        halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER
-                | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER;
-        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel =
-                new android.hardware.soundtrigger.V2_0.ConfidenceLevel();
-        halLevel.userId = 31;
-        halLevel.levelPercent = 43;
-        halExtra.levels.add(halLevel);
-        halEvent.phraseExtras.add(halExtra);
-        return halEvent;
-    }
-
-    private static void validatePhraseRecognitionEvent(PhraseRecognitionEvent event, int status) {
-        validateRecognitionEvent(event.common, status);
-
-        assertEquals(1, event.phraseExtras.length);
-        assertEquals(123, event.phraseExtras[0].id);
-        assertEquals(52, event.phraseExtras[0].confidenceLevel);
-        assertEquals(RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER,
-                event.phraseExtras[0].recognitionModes);
-        assertEquals(1, event.phraseExtras[0].levels.length);
-        assertEquals(31, event.phraseExtras[0].levels[0].userId);
-        assertEquals(43, event.phraseExtras[0].levels[0].levelPercent);
-    }
-
-    private void initService(boolean supportConcurrentCapture) throws RemoteException {
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties properties =
-                    createDefaultProperties(
-                            supportConcurrentCapture);
-            ((android.hardware.soundtrigger.V2_0.ISoundTriggerHw.getPropertiesCallback) invocation.getArgument(
-                    0)).onValues(0,
-                    properties);
-            return null;
-        }).when(mHalDriver).getProperties(any());
-
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-            android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
-                    (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
-            doAnswer(invocation -> {
-                android.hardware.soundtrigger.V2_3.Properties properties =
-                        createDefaultProperties_2_3(
-                                supportConcurrentCapture);
-                ((android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getProperties_2_3Callback)
-                        invocation.getArgument(
-                        0)).onValues(0,
-                        properties);
-                return null;
-            }).when(driver).getProperties_2_3(any());
-        }
-
-        mService = new SoundTriggerMiddlewareImpl(() -> {
-            return mHalDriver;
-        }, mAudioSessionProvider);
-    }
-
-    private Pair<Integer, SoundTriggerHwCallback> loadGenericModel_2_0(ISoundTriggerModule module,
-            int hwHandle) throws RemoteException {
-        SoundModel model = createGenericSoundModel();
-        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel> modelCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel.class);
-        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class);
-        ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback callback =
-                    invocation.getArgument(1);
-            int callbackCookie = invocation.getArgument(2);
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadSoundModelCallback
-                    resultCallback = invocation.getArgument(3);
-
-            // This is the return of this method.
-            resultCallback.onValues(0, hwHandle);
-
-            // This is the async mCallback that comes after.
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent modelEvent =
-                    new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent();
-            modelEvent.status =
-                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.SoundModelStatus.UPDATED;
-            modelEvent.model = hwHandle;
-            callback.soundModelCallback(modelEvent, callbackCookie);
-            return null;
-        }).when(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture(),
-                cookieCaptor.capture(), any());
-
-        when(mAudioSessionProvider.acquireSession()).thenReturn(
-                new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103));
-
-        int handle = module.loadModel(model);
-        verify(mHalDriver).loadSoundModel(any(), any(), anyInt(), any());
-        verify(mAudioSessionProvider).acquireSession();
-
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel hidlModel =
-                modelCaptor.getValue();
-        assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC,
-                hidlModel.type);
-        assertEquals(model.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.uuid));
-        assertEquals(model.vendorUuid, ConversionUtil.hidl2aidlUuid(hidlModel.vendorUuid));
-        assertArrayEquals(new Byte[]{91, 92, 93, 94, 95}, hidlModel.data.toArray());
-
-        return new Pair<>(handle,
-                new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue()));
-    }
-
-    private Pair<Integer, SoundTriggerHwCallback> loadGenericModel_2_1(ISoundTriggerModule module,
-            int hwHandle) throws RemoteException {
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
-        SoundModel model = createGenericSoundModel();
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class);
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
-        ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback callback =
-                    invocation.getArgument(1);
-            int callbackCookie = invocation.getArgument(2);
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback
-                    resultCallback = invocation.getArgument(3);
-
-            // This is the return of this method.
-            resultCallback.onValues(0, hwHandle);
-
-            // This is the async mCallback that comes after.
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent modelEvent =
-                    new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent();
-            modelEvent.header.status =
-                    android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.SoundModelStatus.UPDATED;
-            modelEvent.header.model = hwHandle;
-            callback.soundModelCallback_2_1(modelEvent, callbackCookie);
-            return null;
-        }).when(driver).loadSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
-                cookieCaptor.capture(), any());
-
-        when(mAudioSessionProvider.acquireSession()).thenReturn(
-                new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103));
-
-        int handle = module.loadModel(model);
-        verify(driver).loadSoundModel_2_1(any(), any(), anyInt(), any());
-        verify(mAudioSessionProvider).acquireSession();
-
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel hidlModel =
-                modelCaptor.getValue();
-        assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC,
-                hidlModel.header.type);
-        assertEquals(model.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.header.uuid));
-        assertEquals(model.vendorUuid, ConversionUtil.hidl2aidlUuid(hidlModel.header.vendorUuid));
-        assertArrayEquals(new byte[]{91, 92, 93, 94, 95},
-                HidlMemoryUtil.hidlMemoryToByteArray(hidlModel.data));
-
-        return new Pair<>(handle,
-                new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue()));
-    }
-
     private Pair<Integer, SoundTriggerHwCallback> loadGenericModel(ISoundTriggerModule module,
             int hwHandle) throws RemoteException {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
-            return loadGenericModel_2_1(module, hwHandle);
-        } else {
-            return loadGenericModel_2_0(module, hwHandle);
-        }
+        SoundModel model = TestUtil.createGenericSoundModel();
+        ArgumentCaptor<SoundModel> modelCaptor = ArgumentCaptor.forClass(SoundModel.class);
+        ArgumentCaptor<ISoundTriggerHal.ModelCallback> callbackCaptor = ArgumentCaptor.forClass(
+                ISoundTriggerHal.ModelCallback.class);
+
+        when(mHalDriver.loadSoundModel(any(), any())).thenReturn(hwHandle);
+        when(mAudioSessionProvider.acquireSession()).thenReturn(
+                new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103));
+
+        int handle = module.loadModel(model);
+        verify(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture());
+        verify(mAudioSessionProvider).acquireSession();
+        assertEquals(model, modelCaptor.getValue());
+        return new Pair<>(handle, new SoundTriggerHwCallback(callbackCaptor.getValue()));
     }
 
-    private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel_2_0(ISoundTriggerModule module,
+    private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel(ISoundTriggerModule module,
             int hwHandle) throws RemoteException {
-        PhraseSoundModel model = createPhraseSoundModel();
-        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel>
-                modelCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel.class);
-        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class);
-        ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
+        PhraseSoundModel model = TestUtil.createPhraseSoundModel();
+        ArgumentCaptor<PhraseSoundModel> modelCaptor = ArgumentCaptor.forClass(
+                PhraseSoundModel.class);
+        ArgumentCaptor<ISoundTriggerHal.ModelCallback> callbackCaptor = ArgumentCaptor.forClass(
+                ISoundTriggerHal.ModelCallback.class);
 
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback callback =
-                    invocation.getArgument(
-                            1);
-            int callbackCookie = invocation.getArgument(2);
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadPhraseSoundModelCallback
-                    resultCallback =
-                    invocation.getArgument(
-                            3);
-
-            // This is the return of this method.
-            resultCallback.onValues(0, hwHandle);
-
-            // This is the async mCallback that comes after.
-            android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent modelEvent =
-                    new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent();
-            modelEvent.status =
-                    android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.SoundModelStatus.UPDATED;
-            modelEvent.model = hwHandle;
-            callback.soundModelCallback(modelEvent, callbackCookie);
-            return null;
-        }).when(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture(),
-                cookieCaptor.capture(), any());
-
+        when(mHalDriver.loadPhraseSoundModel(any(), any())).thenReturn(hwHandle);
         when(mAudioSessionProvider.acquireSession()).thenReturn(
                 new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103));
 
         int handle = module.loadPhraseModel(model);
-        verify(mHalDriver).loadPhraseSoundModel(any(), any(), anyInt(), any());
+        verify(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture());
         verify(mAudioSessionProvider).acquireSession();
-
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel hidlModel =
-                modelCaptor.getValue();
-
-        // Validate common part.
-        assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE,
-                hidlModel.common.type);
-        assertEquals(model.common.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.common.uuid));
-        assertEquals(model.common.vendorUuid,
-                ConversionUtil.hidl2aidlUuid(hidlModel.common.vendorUuid));
-        assertArrayEquals(new Byte[]{91, 92, 93, 94, 95}, hidlModel.common.data.toArray());
-
-        // Validate phrase part.
-        assertEquals(1, hidlModel.phrases.size());
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Phrase hidlPhrase =
-                hidlModel.phrases.get(0);
-        assertEquals(123, hidlPhrase.id);
-        assertArrayEquals(new Integer[]{5, 6, 7}, hidlPhrase.users.toArray());
-        assertEquals("locale", hidlPhrase.locale);
-        assertEquals("text", hidlPhrase.text);
-        assertEquals(android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION
-                        | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION,
-                hidlPhrase.recognitionModes);
-
-        return new Pair<>(handle,
-                new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue()));
-    }
-
-    private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel_2_1(ISoundTriggerModule module,
-            int hwHandle) throws RemoteException {
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
-
-        PhraseSoundModel model = createPhraseSoundModel();
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel>
-                modelCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class);
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
-                ArgumentCaptor.forClass(
-                        android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
-        ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
-
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback callback =
-                    invocation.getArgument(
-                            1);
-            int callbackCookie = invocation.getArgument(2);
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback
-                    resultCallback =
-                    invocation.getArgument(
-                            3);
-
-            // This is the return of this method.
-            resultCallback.onValues(0, hwHandle);
-
-            // This is the async mCallback that comes after.
-            android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent modelEvent =
-                    new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent();
-            modelEvent.header.status =
-                    android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.SoundModelStatus.UPDATED;
-            modelEvent.header.model = hwHandle;
-            callback.soundModelCallback_2_1(modelEvent, callbackCookie);
-            return null;
-        }).when(driver).loadPhraseSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
-                cookieCaptor.capture(), any());
-
-        when(mAudioSessionProvider.acquireSession()).thenReturn(
-                new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103));
-
-        int handle = module.loadPhraseModel(model);
-        verify(driver).loadPhraseSoundModel_2_1(any(), any(), anyInt(), any());
-        verify(mAudioSessionProvider).acquireSession();
-
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel hidlModel =
-                modelCaptor.getValue();
-
-        // Validate common part.
-        assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE,
-                hidlModel.common.header.type);
-        assertEquals(model.common.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.common.header.uuid));
-        assertEquals(model.common.vendorUuid,
-                ConversionUtil.hidl2aidlUuid(hidlModel.common.header.vendorUuid));
-        assertArrayEquals(new byte[]{91, 92, 93, 94, 95},
-                HidlMemoryUtil.hidlMemoryToByteArray(hidlModel.common.data));
-
-        // Validate phrase part.
-        assertEquals(1, hidlModel.phrases.size());
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.Phrase hidlPhrase =
-                hidlModel.phrases.get(0);
-        assertEquals(123, hidlPhrase.id);
-        assertArrayEquals(new Integer[]{5, 6, 7}, hidlPhrase.users.toArray());
-        assertEquals("locale", hidlPhrase.locale);
-        assertEquals("text", hidlPhrase.text);
-        assertEquals(android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION
-                        | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION,
-                hidlPhrase.recognitionModes);
-
-        return new Pair<>(handle,
-                new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue()));
-    }
-
-    private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel(
-            ISoundTriggerModule module, int hwHandle) throws RemoteException {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
-            return loadPhraseModel_2_1(module, hwHandle);
-        } else {
-            return loadPhraseModel_2_0(module, hwHandle);
-        }
+        assertEquals(model, modelCaptor.getValue());
+        return new Pair<>(handle, new SoundTriggerHwCallback(callbackCaptor.getValue()));
     }
 
     private void unloadModel(ISoundTriggerModule module, int handle, int hwHandle)
@@ -631,204 +111,35 @@
         verify(mAudioSessionProvider).releaseSession(101);
     }
 
-    private void startRecognition_2_0(ISoundTriggerModule module, int handle,
-            int hwHandle) throws RemoteException {
-        ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig>
-                configCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig.class);
+    private void startRecognition(ISoundTriggerModule module, int handle, int hwHandle)
+            throws RemoteException {
+        ArgumentCaptor<RecognitionConfig> configCaptor = ArgumentCaptor.forClass(
+                RecognitionConfig.class);
 
-        when(mHalDriver.startRecognition(eq(hwHandle), configCaptor.capture(), any(), anyInt()))
-                .thenReturn(0);
-
-        RecognitionConfig config = createRecognitionConfig();
+        RecognitionConfig config = TestUtil.createRecognitionConfig();
 
         module.startRecognition(handle, config);
-        verify(mHalDriver).startRecognition(eq(hwHandle), any(), any(), anyInt());
-
-        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig halConfig =
-                configCaptor.getValue();
-        assertTrue(halConfig.captureRequested);
-        assertEquals(102, halConfig.captureHandle);
-        assertEquals(103, halConfig.captureDevice);
-        assertEquals(1, halConfig.phrases.size());
-        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra =
-                halConfig.phrases.get(0);
-        assertEquals(123, halPhraseExtra.id);
-        assertEquals(4, halPhraseExtra.confidenceLevel);
-        assertEquals(5, halPhraseExtra.recognitionModes);
-        assertEquals(1, halPhraseExtra.levels.size());
-        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0);
-        assertEquals(234, halLevel.userId);
-        assertEquals(34, halLevel.levelPercent);
-        assertArrayEquals(new Byte[]{5, 4, 3, 2, 1}, halConfig.data.toArray());
-    }
-
-    private void startRecognition_2_1(ISoundTriggerModule module, int handle,
-            int hwHandle) throws RemoteException {
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
-
-        ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig>
-                configCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig.class);
-
-        when(driver.startRecognition_2_1(eq(hwHandle), configCaptor.capture(), any(), anyInt()))
-                .thenReturn(0);
-
-        RecognitionConfig config = createRecognitionConfig();
-
-        module.startRecognition(handle, config);
-        verify(driver).startRecognition_2_1(eq(hwHandle), any(), any(), anyInt());
-
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig halConfig =
-                configCaptor.getValue();
-        assertTrue(halConfig.header.captureRequested);
-        assertEquals(102, halConfig.header.captureHandle);
-        assertEquals(103, halConfig.header.captureDevice);
-        assertEquals(1, halConfig.header.phrases.size());
-        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra =
-                halConfig.header.phrases.get(0);
-        assertEquals(123, halPhraseExtra.id);
-        assertEquals(4, halPhraseExtra.confidenceLevel);
-        assertEquals(5, halPhraseExtra.recognitionModes);
-        assertEquals(1, halPhraseExtra.levels.size());
-        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0);
-        assertEquals(234, halLevel.userId);
-        assertEquals(34, halLevel.levelPercent);
-        assertArrayEquals(new byte[]{5, 4, 3, 2, 1},
-                HidlMemoryUtil.hidlMemoryToByteArray(halConfig.data));
-    }
-
-    private void startRecognition_2_3(ISoundTriggerModule module, int handle,
-            int hwHandle) throws RemoteException {
-        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
-
-        ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig>
-                configCaptor = ArgumentCaptor.forClass(
-                android.hardware.soundtrigger.V2_3.RecognitionConfig.class);
-
-        when(driver.startRecognition_2_3(eq(hwHandle), configCaptor.capture())).thenReturn(0);
-
-        RecognitionConfig config = createRecognitionConfig();
-
-        module.startRecognition(handle, config);
-        verify(driver).startRecognition_2_3(eq(hwHandle), any());
-
-        android.hardware.soundtrigger.V2_3.RecognitionConfig halConfigExtended =
-                configCaptor.getValue();
-        android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig halConfig_2_1 =
-                halConfigExtended.base;
-
-        assertTrue(halConfig_2_1.header.captureRequested);
-        assertEquals(102, halConfig_2_1.header.captureHandle);
-        assertEquals(103, halConfig_2_1.header.captureDevice);
-        assertEquals(1, halConfig_2_1.header.phrases.size());
-        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra =
-                halConfig_2_1.header.phrases.get(0);
-        assertEquals(123, halPhraseExtra.id);
-        assertEquals(4, halPhraseExtra.confidenceLevel);
-        assertEquals(5, halPhraseExtra.recognitionModes);
-        assertEquals(1, halPhraseExtra.levels.size());
-        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0);
-        assertEquals(234, halLevel.userId);
-        assertEquals(34, halLevel.levelPercent);
-        assertArrayEquals(new byte[]{5, 4, 3, 2, 1},
-                HidlMemoryUtil.hidlMemoryToByteArray(halConfig_2_1.data));
-        assertEquals(AudioCapabilities.ECHO_CANCELLATION
-                | AudioCapabilities.NOISE_SUPPRESSION, halConfigExtended.audioCapabilities);
-    }
-
-    private void startRecognition(ISoundTriggerModule module, int handle,
-            int hwHandle) throws RemoteException {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-            startRecognition_2_3(module, handle, hwHandle);
-        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
-            startRecognition_2_1(module, handle, hwHandle);
-        } else {
-            startRecognition_2_0(module, handle, hwHandle);
-        }
-    }
-
-    private RecognitionConfig createRecognitionConfig() {
-        RecognitionConfig config = new RecognitionConfig();
-        config.captureRequested = true;
-        config.phraseRecognitionExtras = new PhraseRecognitionExtra[]{new PhraseRecognitionExtra()};
-        config.phraseRecognitionExtras[0].id = 123;
-        config.phraseRecognitionExtras[0].confidenceLevel = 4;
-        config.phraseRecognitionExtras[0].recognitionModes = 5;
-        config.phraseRecognitionExtras[0].levels = new ConfidenceLevel[]{new ConfidenceLevel()};
-        config.phraseRecognitionExtras[0].levels[0].userId = 234;
-        config.phraseRecognitionExtras[0].levels[0].levelPercent = 34;
-        config.data = new byte[]{5, 4, 3, 2, 1};
-        config.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
-                | AudioCapabilities.NOISE_SUPPRESSION;
-        return config;
+        verify(mHalDriver).startRecognition(eq(hwHandle), eq(103), eq(102), configCaptor.capture());
+        assertEquals(config, configCaptor.getValue());
     }
 
     private void stopRecognition(ISoundTriggerModule module, int handle, int hwHandle)
             throws RemoteException {
-        when(mHalDriver.stopRecognition(hwHandle)).thenReturn(0);
         module.stopRecognition(handle);
         verify(mHalDriver).stopRecognition(hwHandle);
     }
 
-    private void verifyNotStartRecognition() throws RemoteException {
-        verify(mHalDriver, never()).startRecognition(anyInt(), any(), any(), anyInt());
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) {
-            verify((android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver,
-                    never()).startRecognition_2_1(anyInt(), any(), any(), anyInt());
-        } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-            verify((android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver,
-                    never()).startRecognition_2_3(anyInt(), any());
-        }
-    }
-
-
     @Before
     public void setUp() throws Exception {
         clearInvocations(mHalDriver);
         clearInvocations(mAudioSessionProvider);
+        when(mHalDriver.getProperties()).thenReturn(TestUtil.createDefaultProperties(false));
+        mService = new SoundTriggerMiddlewareImpl(() -> mHalDriver, mAudioSessionProvider);
+    }
 
-        // This binder is associated with the mock, so it can be cast to either version of the
-        // HAL interface.
-        final IHwBinder binder = new IHwBinder() {
-            @Override
-            public void transact(int code, HwParcel request, HwParcel reply, int flags)
-                    throws RemoteException {
-                // This is a little hacky, but a very easy way to gracefully reject a request for
-                // an unsupported interface (after queryLocalInterface() returns null, the client
-                // will attempt a remote transaction to obtain the interface. RemoteException will
-                // cause it to give up).
-                throw new RemoteException();
-            }
-
-            @Override
-            public IHwInterface queryLocalInterface(String descriptor) {
-                if (descriptor.equals("android.hardware.soundtrigger@2.0::ISoundTriggerHw")
-                        || descriptor.equals("android.hardware.soundtrigger@2.1::ISoundTriggerHw")
-                        && mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw
-                        || descriptor.equals("android.hardware.soundtrigger@2.2::ISoundTriggerHw")
-                        && mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw
-                        || descriptor.equals("android.hardware.soundtrigger@2.3::ISoundTriggerHw")
-                        && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-                    return mHalDriver;
-                }
-                return null;
-            }
-
-            @Override
-            public boolean linkToDeath(DeathRecipient recipient, long cookie) {
-                return true;
-            }
-
-            @Override
-            public boolean unlinkToDeath(DeathRecipient recipient) {
-                return true;
-            }
-        };
-
-        when(mHalDriver.asBinder()).thenReturn(binder);
+    @After
+    public void tearDown() {
+        verify(mHalDriver, never()).reboot();
     }
 
     @Test
@@ -836,58 +147,28 @@
     }
 
     @Test
-    public void testListModules() throws Exception {
-        initService(true);
+    public void testListModules() {
         // Note: input and output properties are NOT the same type, even though they are in any way
         // equivalent. One is a type that's exposed by the HAL and one is a type that's exposed by
         // the service. The service actually performs a (trivial) conversion between the two.
         SoundTriggerModuleDescriptor[] allDescriptors = mService.listModules();
         assertEquals(1, allDescriptors.length);
 
-        SoundTriggerModuleProperties properties = allDescriptors[0].properties;
-
-        validateDefaultProperties(properties, true);
-        verifyNotGetProperties();
+        Properties properties = allDescriptors[0].properties;
+        assertEquals(TestUtil.createDefaultProperties(false), properties);
     }
 
     @Test
     public void testAttachDetach() throws Exception {
         // Normal attachment / detachment.
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(true);
-        assertNotNull(module);
-        module.detach();
-    }
-
-    @Test
-    public void testAttachDetachNotAvailable() throws Exception {
-        // Attachment / detachment during external capture, with a module not supporting concurrent
-        // capture.
-        initService(false);
-        ISoundTriggerCallback callback = createCallbackMock();
-        ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(false);
-        assertNotNull(module);
-        module.detach();
-    }
-
-    @Test
-    public void testAttachDetachAvailable() throws Exception {
-        // Attachment / detachment during external capture, with a module supporting concurrent
-        // capture.
-        initService(true);
-        ISoundTriggerCallback callback = createCallbackMock();
-        ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(true);
         assertNotNull(module);
         module.detach();
     }
 
     @Test
     public void testLoadUnloadModel() throws Exception {
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -898,8 +179,26 @@
     }
 
     @Test
+    public void testLoadPreemptModel() throws Exception {
+        ISoundTriggerCallback callback = createCallbackMock();
+        ISoundTriggerModule module = mService.attach(0, callback);
+
+        final int hwHandle = 7;
+        Pair<Integer, SoundTriggerHwCallback> loadResult = loadGenericModel(module, hwHandle);
+
+        int handle = loadResult.first;
+        SoundTriggerHwCallback hwCallback = loadResult.second;
+
+        // Signal preemption.
+        hwCallback.sendUnloadEvent(hwHandle);
+
+        verify(callback).onModelUnloaded(handle);
+
+        module.detach();
+    }
+
+    @Test
     public void testLoadUnloadPhraseModel() throws Exception {
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -911,7 +210,6 @@
 
     @Test
     public void testStartStopRecognition() throws Exception {
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -931,8 +229,31 @@
     }
 
     @Test
+    public void testStartRecognitionBusy() throws Exception {
+        ISoundTriggerCallback callback = createCallbackMock();
+        ISoundTriggerModule module = mService.attach(0, callback);
+
+        // Load the model.
+        final int hwHandle = 7;
+        int handle = loadGenericModel(module, hwHandle).first;
+
+        // Start the model.
+        doThrow(new RecoverableException(Status.RESOURCE_CONTENTION)).when(
+                mHalDriver).startRecognition(eq(7), eq(103), eq(102), any());
+
+        try {
+            RecognitionConfig config = TestUtil.createRecognitionConfig();
+            module.startRecognition(handle, config);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.RESOURCE_CONTENTION, e.errorCode);
+        }
+
+        verify(mHalDriver).startRecognition(eq(7), eq(103), eq(102), any());
+    }
+
+    @Test
     public void testStartStopPhraseRecognition() throws Exception {
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -953,7 +274,6 @@
 
     @Test
     public void testRecognition() throws Exception {
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -967,15 +287,15 @@
         startRecognition(module, handle, hwHandle);
 
         // Signal a capture from the driver.
-        hwCallback.sendRecognitionEvent(hwHandle,
-                android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS);
+        RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
+                RecognitionStatus.SUCCESS);
 
         ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
                 RecognitionEvent.class);
-        verify(callback).onRecognition(eq(handle), eventCaptor.capture());
+        verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
-        validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.SUCCESS);
+        assertEquals(event, eventCaptor.getValue());
 
         // Unload the model.
         unloadModel(module, handle, hwHandle);
@@ -984,7 +304,6 @@
 
     @Test
     public void testPhraseRecognition() throws Exception {
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -998,15 +317,15 @@
         startRecognition(module, handle, hwHandle);
 
         // Signal a capture from the driver.
-        hwCallback.sendPhraseRecognitionEvent(hwHandle,
-                android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS);
+        PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+                RecognitionStatus.SUCCESS);
 
         ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
                 PhraseRecognitionEvent.class);
-        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture());
+        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
-        validatePhraseRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.SUCCESS);
+        assertEquals(event, eventCaptor.getValue());
 
         // Unload the model.
         unloadModel(module, handle, hwHandle);
@@ -1015,14 +334,6 @@
 
     @Test
     public void testForceRecognition() throws Exception {
-        if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw)) {
-            return;
-        }
-
-        android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver;
-
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -1037,18 +348,49 @@
 
         // Force a trigger.
         module.forceRecognitionEvent(handle);
-        verify(driver).getModelState(hwHandle);
+        verify(mHalDriver).forceRecognitionEvent(hwHandle);
 
         // Signal a capture from the driver.
-        // '3' means 'forced', there's no constant for that in the HAL.
-        hwCallback.sendRecognitionEvent(hwHandle, 3);
+        RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
+                RecognitionStatus.FORCED);
 
         ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
                 RecognitionEvent.class);
-        verify(callback).onRecognition(eq(handle), eventCaptor.capture());
+        verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
-        validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED);
+        assertEquals(event, eventCaptor.getValue());
+
+        // Stop the recognition.
+        stopRecognition(module, handle, hwHandle);
+
+        // Unload the model.
+        unloadModel(module, handle, hwHandle);
+        module.detach();
+    }
+
+    @Test
+    public void testForceRecognitionNotSupported() throws Exception {
+        ISoundTriggerCallback callback = createCallbackMock();
+        ISoundTriggerModule module = mService.attach(0, callback);
+
+        // Load the model.
+        final int hwHandle = 17;
+        Pair<Integer, SoundTriggerHwCallback> modelHandles = loadGenericModel(module, hwHandle);
+        int handle = modelHandles.first;
+
+        // Initiate a recognition.
+        startRecognition(module, handle, hwHandle);
+
+        // Force a trigger.
+        doThrow(new RecoverableException(Status.OPERATION_NOT_SUPPORTED)).when(
+                mHalDriver).forceRecognitionEvent(hwHandle);
+        try {
+            module.forceRecognitionEvent(handle);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode);
+        }
 
         // Stop the recognition.
         stopRecognition(module, handle, hwHandle);
@@ -1060,14 +402,6 @@
 
     @Test
     public void testForcePhraseRecognition() throws Exception {
-        if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw)) {
-            return;
-        }
-
-        android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver;
-
-        initService(true);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
 
@@ -1082,18 +416,49 @@
 
         // Force a trigger.
         module.forceRecognitionEvent(handle);
-        verify(driver).getModelState(hwHandle);
+        verify(mHalDriver).forceRecognitionEvent(hwHandle);
 
         // Signal a capture from the driver.
-        // '3' means 'forced', there's no constant for that in the HAL.
-        hwCallback.sendPhraseRecognitionEvent(hwHandle, 3);
+        PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+                RecognitionStatus.FORCED);
 
         ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
                 PhraseRecognitionEvent.class);
-        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture());
+        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
-        validatePhraseRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED);
+        assertEquals(event, eventCaptor.getValue());
+
+        // Stop the recognition.
+        stopRecognition(module, handle, hwHandle);
+
+        // Unload the model.
+        unloadModel(module, handle, hwHandle);
+        module.detach();
+    }
+
+    @Test
+    public void testForcePhraseRecognitionNotSupported() throws Exception {
+        ISoundTriggerCallback callback = createCallbackMock();
+        ISoundTriggerModule module = mService.attach(0, callback);
+
+        // Load the model.
+        final int hwHandle = 17;
+        Pair<Integer, SoundTriggerHwCallback> modelHandles = loadPhraseModel(module, hwHandle);
+        int handle = modelHandles.first;
+
+        // Initiate a recognition.
+        startRecognition(module, handle, hwHandle);
+
+        // Force a trigger.
+        doThrow(new RecoverableException(Status.OPERATION_NOT_SUPPORTED)).when(
+                mHalDriver).forceRecognitionEvent(hwHandle);
+        try {
+            module.forceRecognitionEvent(handle);
+            fail("Expected an exception");
+        } catch (RecoverableException e) {
+            assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode);
+        }
 
         // Stop the recognition.
         stopRecognition(module, handle, hwHandle);
@@ -1106,46 +471,28 @@
     @Test
     public void testAbortRecognition() throws Exception {
         // Make sure the HAL doesn't support concurrent capture.
-        initService(false);
-        mService.setCaptureState(false);
-
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(true);
 
         // Load the model.
         final int hwHandle = 11;
-        int handle = loadGenericModel(module, hwHandle).first;
+        Pair<Integer, SoundTriggerHwCallback> loadResult = loadGenericModel(module, hwHandle);
+        int handle = loadResult.first;
+        SoundTriggerHwCallback hwCallback = loadResult.second;
 
         // Initiate a recognition.
         startRecognition(module, handle, hwHandle);
 
         // Abort.
-        mService.setCaptureState(true);
+        hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED);
 
         ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
                 RecognitionEvent.class);
-        verify(callback).onRecognition(eq(handle), eventCaptor.capture());
+        verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
         assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
 
-        // Make sure we are notified of the lost availability.
-        verify(callback).onRecognitionAvailabilityChange(false);
-
-        // Attempt to start a new recognition - should get an abort event immediately, without
-        // involving the HAL.
-        clearInvocations(callback);
-        clearInvocations(mHalDriver);
-        module.startRecognition(handle, createRecognitionConfig());
-        verify(callback).onRecognition(eq(handle), eventCaptor.capture());
-        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
-        verifyNotStartRecognition();
-
-        // Now enable it and make sure we are notified.
-        mService.setCaptureState(false);
-        verify(callback).onRecognitionAvailabilityChange(true);
-
         // Unload the model.
         unloadModel(module, handle, hwHandle);
         module.detach();
@@ -1154,298 +501,124 @@
     @Test
     public void testAbortPhraseRecognition() throws Exception {
         // Make sure the HAL doesn't support concurrent capture.
-        initService(false);
-        mService.setCaptureState(false);
-
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(true);
 
         // Load the model.
         final int hwHandle = 11;
-        int handle = loadPhraseModel(module, hwHandle).first;
+        Pair<Integer, SoundTriggerHwCallback> loadResult = loadPhraseModel(module, hwHandle);
+        int handle = loadResult.first;
+        SoundTriggerHwCallback hwCallback = loadResult.second;
 
         // Initiate a recognition.
         startRecognition(module, handle, hwHandle);
 
         // Abort.
-        mService.setCaptureState(true);
+        hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED);
 
         ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
                 PhraseRecognitionEvent.class);
-        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture());
+        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
         assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
 
-        // Make sure we are notified of the lost availability.
-        verify(callback).onRecognitionAvailabilityChange(false);
-
-        // Attempt to start a new recognition - should get an abort event immediately, without
-        // involving the HAL.
-        clearInvocations(callback);
-        clearInvocations(mHalDriver);
-        module.startRecognition(handle, createRecognitionConfig());
-        verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture());
-        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
-        verifyNotStartRecognition();
-
-        // Now enable it and make sure we are notified.
-        mService.setCaptureState(false);
-        verify(callback).onRecognitionAvailabilityChange(true);
-
         // Unload the model.
         unloadModel(module, handle, hwHandle);
         module.detach();
     }
 
     @Test
-    public void testNotAbortRecognitionConcurrent() throws Exception {
-        // Make sure the HAL supports concurrent capture.
-        initService(true);
-
-        ISoundTriggerCallback callback = createCallbackMock();
-        ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(true);
-        clearInvocations(callback);
-
-        // Load the model.
-        final int hwHandle = 13;
-        int handle = loadGenericModel(module, hwHandle).first;
-
-        // Initiate a recognition.
-        startRecognition(module, handle, hwHandle);
-
-        // Signal concurrent capture. Shouldn't abort.
-        mService.setCaptureState(true);
-        verify(callback, never()).onRecognition(anyInt(), any());
-        verify(callback, never()).onRecognitionAvailabilityChange(anyBoolean());
-
-        // Stop the recognition.
-        stopRecognition(module, handle, hwHandle);
-
-        // Initiating a new one should work fine.
-        clearInvocations(mHalDriver);
-        startRecognition(module, handle, hwHandle);
-        verify(callback, never()).onRecognition(anyInt(), any());
-        stopRecognition(module, handle, hwHandle);
-
-        // Unload the model.
-        module.unloadModel(handle);
-        module.detach();
-    }
-
-    @Test
-    public void testNotAbortPhraseRecognitionConcurrent() throws Exception {
-        // Make sure the HAL supports concurrent capture.
-        initService(true);
-
-        ISoundTriggerCallback callback = createCallbackMock();
-        ISoundTriggerModule module = mService.attach(0, callback);
-        verify(callback).onRecognitionAvailabilityChange(true);
-        clearInvocations(callback);
-
-        // Load the model.
-        final int hwHandle = 13;
-        int handle = loadPhraseModel(module, hwHandle).first;
-
-        // Initiate a recognition.
-        startRecognition(module, handle, hwHandle);
-
-        // Signal concurrent capture. Shouldn't abort.
-        mService.setCaptureState(true);
-        verify(callback, never()).onPhraseRecognition(anyInt(), any());
-        verify(callback, never()).onRecognitionAvailabilityChange(anyBoolean());
-
-        // Stop the recognition.
-        stopRecognition(module, handle, hwHandle);
-
-        // Initiating a new one should work fine.
-        clearInvocations(mHalDriver);
-        startRecognition(module, handle, hwHandle);
-        verify(callback, never()).onRecognition(anyInt(), any());
-        stopRecognition(module, handle, hwHandle);
-
-        // Unload the model.
-        module.unloadModel(handle);
-        module.detach();
-    }
-
-    @Test
     public void testParameterSupported() throws Exception {
-        if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) {
-            return;
-        }
-
-        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
-
-        initService(false);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
         final int hwHandle = 12;
         int modelHandle = loadGenericModel(module, hwHandle).first;
 
-        doAnswer((Answer<Void>) invocation -> {
-            android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback
-                    resultCallback = invocation.getArgument(2);
-            android.hardware.soundtrigger.V2_3.ModelParameterRange range =
-                    new android.hardware.soundtrigger.V2_3.ModelParameterRange();
-            range.start = 23;
-            range.end = 45;
-            OptionalModelParameterRange optionalRange = new OptionalModelParameterRange();
-            optionalRange.range(range);
-            resultCallback.onValues(0, optionalRange);
-            return null;
-        }).when(driver).queryParameter(eq(hwHandle),
-                eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any());
+        ModelParameterRange halRange = new ModelParameterRange();
+        halRange.minInclusive = 23;
+        halRange.maxInclusive = 45;
+
+        when(mHalDriver.queryParameter(eq(hwHandle),
+                eq(ModelParameter.THRESHOLD_FACTOR))).thenReturn(halRange);
 
         ModelParameterRange range = module.queryModelParameterSupport(modelHandle,
                 ModelParameter.THRESHOLD_FACTOR);
 
-        verify(driver).queryParameter(eq(hwHandle),
-                eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any());
+        verify(mHalDriver).queryParameter(eq(hwHandle), eq(ModelParameter.THRESHOLD_FACTOR));
 
-        assertEquals(23, range.minInclusive);
-        assertEquals(45, range.maxInclusive);
-    }
-
-    @Test
-    public void testParameterNotSupportedOld() throws Exception {
-        if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) {
-            return;
-        }
-
-        initService(false);
-        ISoundTriggerCallback callback = createCallbackMock();
-        ISoundTriggerModule module = mService.attach(0, callback);
-        final int hwHandle = 13;
-        int modelHandle = loadGenericModel(module, hwHandle).first;
-
-        ModelParameterRange range = module.queryModelParameterSupport(modelHandle,
-                ModelParameter.THRESHOLD_FACTOR);
-
-        assertNull(range);
+        assertEquals(halRange, range);
     }
 
     @Test
     public void testParameterNotSupported() throws Exception {
-        if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) {
-            return;
-        }
-
-        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
-
-        initService(false);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
         final int hwHandle = 13;
         int modelHandle = loadGenericModel(module, hwHandle).first;
 
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback
-                    resultCallback = invocation.getArgument(2);
-            // This is the return of this method.
-            resultCallback.onValues(0, new OptionalModelParameterRange());
-            return null;
-        }).when(driver).queryParameter(eq(hwHandle),
-                eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any());
+        when(mHalDriver.queryParameter(eq(hwHandle),
+                eq(ModelParameter.THRESHOLD_FACTOR))).thenReturn(null);
 
         ModelParameterRange range = module.queryModelParameterSupport(modelHandle,
                 ModelParameter.THRESHOLD_FACTOR);
 
-        verify(driver).queryParameter(eq(hwHandle),
-                eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any());
+        verify(mHalDriver).queryParameter(eq(hwHandle), eq(ModelParameter.THRESHOLD_FACTOR));
 
         assertNull(range);
     }
 
     @Test
     public void testGetParameter() throws Exception {
-        if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) {
-            return;
-        }
-
-        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
-
-        initService(false);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
         final int hwHandle = 14;
         int modelHandle = loadGenericModel(module, hwHandle).first;
 
-        doAnswer(invocation -> {
-            android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getParameterCallback
-                    resultCallback = invocation.getArgument(2);
-            // This is the return of this method.
-            resultCallback.onValues(0, 234);
-            return null;
-        }).when(driver).getParameter(eq(hwHandle),
-                eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any());
+        when(mHalDriver.getModelParameter(hwHandle, ModelParameter.THRESHOLD_FACTOR)).thenReturn(
+                234);
 
         int value = module.getModelParameter(modelHandle, ModelParameter.THRESHOLD_FACTOR);
 
-        verify(driver).getParameter(eq(hwHandle),
-                eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any());
+        verify(mHalDriver).getModelParameter(hwHandle, ModelParameter.THRESHOLD_FACTOR);
 
         assertEquals(234, value);
     }
 
     @Test
     public void testSetParameter() throws Exception {
-        if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) {
-            return;
-        }
-
-        android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver =
-                (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver;
-
-        initService(false);
         ISoundTriggerCallback callback = createCallbackMock();
         ISoundTriggerModule module = mService.attach(0, callback);
         final int hwHandle = 17;
         int modelHandle = loadGenericModel(module, hwHandle).first;
 
-        when(driver.setParameter(hwHandle,
-                android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR,
-                456)).thenReturn(0);
-
         module.setModelParameter(modelHandle, ModelParameter.THRESHOLD_FACTOR, 456);
 
-        verify(driver).setParameter(hwHandle,
-                android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR, 456);
+        verify(mHalDriver).setModelParameter(hwHandle, ModelParameter.THRESHOLD_FACTOR, 456);
     }
 
     private static class SoundTriggerHwCallback {
-        private final android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback mCallback;
-        private final int mCookie;
+        private final ISoundTriggerHal.ModelCallback mCallback;
 
-        SoundTriggerHwCallback(android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback callback,
-                int cookie) {
+        SoundTriggerHwCallback(ISoundTriggerHal.ModelCallback callback) {
             mCallback = callback;
-            mCookie = cookie;
         }
 
-        private void sendRecognitionEvent(int hwHandle, int status) throws RemoteException {
-            if (mCallback instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) {
-                ((android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) mCallback).recognitionCallback_2_1(
-                        createRecognitionEvent_2_1(hwHandle, status), mCookie);
-            } else {
-                mCallback.recognitionCallback(createRecognitionEvent_2_0(hwHandle, status),
-                        mCookie);
-            }
+        private RecognitionEvent sendRecognitionEvent(int hwHandle, @RecognitionStatus int status) {
+            RecognitionEvent event = TestUtil.createRecognitionEvent(status);
+            mCallback.recognitionCallback(hwHandle, event);
+            return event;
         }
 
-        private void sendPhraseRecognitionEvent(int hwHandle, int status) throws RemoteException {
-            if (mCallback instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) {
-                ((android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) mCallback).phraseRecognitionCallback_2_1(
-                        createPhraseRecognitionEvent_2_1(hwHandle, status), mCookie);
-            } else {
-                mCallback.phraseRecognitionCallback(
-                        createPhraseRecognitionEvent_2_0(hwHandle, status), mCookie);
-            }
+        private PhraseRecognitionEvent sendPhraseRecognitionEvent(int hwHandle,
+                @RecognitionStatus int status) {
+            PhraseRecognitionEvent event = TestUtil.createPhraseRecognitionEvent(status);
+            mCallback.phraseRecognitionCallback(hwHandle, event);
+            return event;
+        }
+
+        private void sendUnloadEvent(int hwHandle) {
+            mCallback.modelUnloaded(hwHandle);
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
new file mode 100644
index 0000000..4eca298
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.hardware.soundtrigger.V2_1.ISoundTriggerHw;
+import android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback;
+import android.media.audio.common.AudioChannelMask;
+import android.media.audio.common.AudioConfig;
+import android.media.audio.common.AudioFormat;
+import android.media.soundtrigger.AudioCapabilities;
+import android.media.soundtrigger.ConfidenceLevel;
+import android.media.soundtrigger.Phrase;
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.PhraseSoundModel;
+import android.media.soundtrigger.Properties;
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionMode;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
+import android.os.HidlMemoryUtil;
+import android.os.ParcelFileDescriptor;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Test utilities, aimed at generating populated objects of the various types and validating
+ * corresponding objects generated by the system under test.
+ */
+class TestUtil {
+    static SoundModel createGenericSoundModel() {
+        return createSoundModel(SoundModelType.GENERIC);
+    }
+
+    private static SoundModel createSoundModel(@SoundModelType int type) {
+        SoundModel model = new SoundModel();
+        model.type = type;
+        model.uuid = "12345678-2345-3456-4567-abcdef987654";
+        model.vendorUuid = "87654321-5432-6543-7654-456789fedcba";
+        byte[] data = new byte[]{91, 92, 93, 94, 95};
+        model.data = new ParcelFileDescriptor(byteArrayToFileDescriptor(data));
+        model.dataSize = data.length;
+        return model;
+    }
+
+    private static void validateSoundModel_2_1(ISoundTriggerHw.SoundModel model, int type) {
+        assertEquals(type, model.header.type);
+        assertEquals("12345678-2345-3456-4567-abcdef987654",
+                ConversionUtil.hidl2aidlUuid(model.header.uuid));
+        assertEquals("87654321-5432-6543-7654-456789fedcba",
+                ConversionUtil.hidl2aidlUuid(model.header.vendorUuid));
+        assertArrayEquals(new byte[]{91, 92, 93, 94, 95},
+                HidlMemoryUtil.hidlMemoryToByteArray(model.data));
+    }
+
+    private static void validateSoundModel_2_0(
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model, int type) {
+        assertEquals(type, model.type);
+        assertEquals("12345678-2345-3456-4567-abcdef987654",
+                ConversionUtil.hidl2aidlUuid(model.uuid));
+        assertEquals("87654321-5432-6543-7654-456789fedcba",
+                ConversionUtil.hidl2aidlUuid(model.vendorUuid));
+        assertArrayEquals(new Byte[]{91, 92, 93, 94, 95}, model.data.toArray());
+    }
+
+    static void validateGenericSoundModel_2_1(ISoundTriggerHw.SoundModel model) {
+        validateSoundModel_2_1(model, android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC);
+    }
+
+    static void validateGenericSoundModel_2_0(
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model) {
+        validateSoundModel_2_0(model, android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC);
+    }
+
+    static PhraseSoundModel createPhraseSoundModel() {
+        PhraseSoundModel model = new PhraseSoundModel();
+        model.common = createSoundModel(SoundModelType.KEYPHRASE);
+        model.phrases = new Phrase[1];
+        model.phrases[0] = new Phrase();
+        model.phrases[0].id = 123;
+        model.phrases[0].users = new int[]{5, 6, 7};
+        model.phrases[0].locale = "locale";
+        model.phrases[0].text = "text";
+        model.phrases[0].recognitionModes =
+                RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION;
+        return model;
+    }
+
+    static void validatePhraseSoundModel_2_1(ISoundTriggerHw.PhraseSoundModel model) {
+        validateSoundModel_2_1(model.common,
+                android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE);
+        validatePhrases_2_0(model.phrases);
+    }
+
+    static void validatePhraseSoundModel_2_0(
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel model) {
+        validateSoundModel_2_0(model.common,
+                android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE);
+        validatePhrases_2_0(model.phrases);
+    }
+
+    private static void validatePhrases_2_0(
+            List<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Phrase> phrases) {
+        assertEquals(1, phrases.size());
+        assertEquals(123, phrases.get(0).id);
+        assertArrayEquals(new Integer[]{5, 6, 7}, phrases.get(0).users.toArray());
+        assertEquals("locale", phrases.get(0).locale);
+        assertEquals("text", phrases.get(0).text);
+        assertEquals(RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION,
+                phrases.get(0).recognitionModes);
+    }
+
+    static android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties createDefaultProperties_2_0(
+            boolean supportConcurrentCapture) {
+        android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties properties =
+                new android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties();
+        properties.implementor = "implementor";
+        properties.description = "description";
+        properties.version = 123;
+        properties.uuid.timeLow = 1;
+        properties.uuid.timeMid = 2;
+        properties.uuid.versionAndTimeHigh = 3;
+        properties.uuid.variantAndClockSeqHigh = 4;
+        properties.uuid.node = new byte[]{5, 6, 7, 8, 9, 10};
+
+        properties.maxSoundModels = 456;
+        properties.maxKeyPhrases = 567;
+        properties.maxUsers = 678;
+        properties.recognitionModes =
+                android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER
+                        | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION
+                        | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION
+                        | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER;
+        properties.captureTransition = true;
+        properties.maxBufferMs = 321;
+        properties.concurrentCapture = supportConcurrentCapture;
+        properties.triggerInEvent = true;
+        properties.powerConsumptionMw = 432;
+        return properties;
+    }
+
+    static android.hardware.soundtrigger.V2_3.Properties createDefaultProperties_2_3(
+            boolean supportConcurrentCapture) {
+        android.hardware.soundtrigger.V2_3.Properties properties =
+                new android.hardware.soundtrigger.V2_3.Properties();
+        properties.base = createDefaultProperties_2_0(supportConcurrentCapture);
+        properties.supportedModelArch = "supportedModelArch";
+        properties.audioCapabilities =
+                android.hardware.soundtrigger.V2_3.AudioCapabilities.ECHO_CANCELLATION
+                        | android.hardware.soundtrigger.V2_3.AudioCapabilities.NOISE_SUPPRESSION;
+        return properties;
+    }
+
+    static Properties createDefaultProperties(boolean supportConcurrentCapture) {
+        Properties properties = new Properties();
+        properties.implementor = "implementor";
+        properties.description = "description";
+        properties.version = 123;
+        properties.uuid = "00000001-0002-0003-0004-05060708090a";
+        properties.maxSoundModels = 456;
+        properties.maxKeyPhrases = 567;
+        properties.maxUsers = 678;
+        properties.recognitionModes =
+                RecognitionMode.VOICE_TRIGGER
+                        | RecognitionMode.USER_IDENTIFICATION
+                        | RecognitionMode.USER_AUTHENTICATION
+                        | RecognitionMode.GENERIC_TRIGGER;
+        properties.captureTransition = true;
+        properties.maxBufferMs = 321;
+        properties.concurrentCapture = supportConcurrentCapture;
+        properties.triggerInEvent = true;
+        properties.powerConsumptionMw = 432;
+        properties.supportedModelArch = "supportedModelArch";
+        properties.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
+                | AudioCapabilities.NOISE_SUPPRESSION;
+        return properties;
+    }
+
+    static void validateDefaultProperties(Properties properties,
+            boolean supportConcurrentCapture) {
+        validateDefaultProperties(properties, supportConcurrentCapture,
+                AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION,
+                "supportedModelArch");
+    }
+
+    static void validateDefaultProperties(Properties properties,
+            boolean supportConcurrentCapture, @AudioCapabilities int audioCapabilities,
+            @NonNull String supportedModelArch) {
+        assertEquals("implementor", properties.implementor);
+        assertEquals("description", properties.description);
+        assertEquals(123, properties.version);
+        assertEquals("00000001-0002-0003-0004-05060708090a", properties.uuid);
+        assertEquals(456, properties.maxSoundModels);
+        assertEquals(567, properties.maxKeyPhrases);
+        assertEquals(678, properties.maxUsers);
+        assertEquals(RecognitionMode.GENERIC_TRIGGER
+                | RecognitionMode.USER_AUTHENTICATION
+                | RecognitionMode.USER_IDENTIFICATION
+                | RecognitionMode.VOICE_TRIGGER, properties.recognitionModes);
+        assertTrue(properties.captureTransition);
+        assertEquals(321, properties.maxBufferMs);
+        assertEquals(supportConcurrentCapture, properties.concurrentCapture);
+        assertTrue(properties.triggerInEvent);
+        assertEquals(432, properties.powerConsumptionMw);
+        assertEquals(supportedModelArch, properties.supportedModelArch);
+        assertEquals(audioCapabilities, properties.audioCapabilities);
+    }
+
+    static RecognitionConfig createRecognitionConfig() {
+        RecognitionConfig config = new RecognitionConfig();
+        config.captureRequested = true;
+        config.phraseRecognitionExtras = new PhraseRecognitionExtra[]{new PhraseRecognitionExtra()};
+        config.phraseRecognitionExtras[0].id = 123;
+        config.phraseRecognitionExtras[0].confidenceLevel = 4;
+        config.phraseRecognitionExtras[0].recognitionModes = 5;
+        config.phraseRecognitionExtras[0].levels = new ConfidenceLevel[]{new ConfidenceLevel()};
+        config.phraseRecognitionExtras[0].levels[0].userId = 234;
+        config.phraseRecognitionExtras[0].levels[0].levelPercent = 34;
+        config.data = new byte[]{5, 4, 3, 2, 1};
+        config.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
+                | AudioCapabilities.NOISE_SUPPRESSION;
+        return config;
+    }
+
+    static void validateRecognitionConfig_2_0(
+            android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig config,
+            int captureDevice, int captureHandle) {
+        assertTrue(config.captureRequested);
+        assertEquals(captureDevice, config.captureDevice);
+        assertEquals(captureHandle, config.captureHandle);
+        assertEquals(1, config.phrases.size());
+        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra =
+                config.phrases.get(0);
+        assertEquals(123, halPhraseExtra.id);
+        assertEquals(4, halPhraseExtra.confidenceLevel);
+        assertEquals(5, halPhraseExtra.recognitionModes);
+        assertEquals(1, halPhraseExtra.levels.size());
+        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0);
+        assertEquals(234, halLevel.userId);
+        assertEquals(34, halLevel.levelPercent);
+        assertArrayEquals(new Byte[]{5, 4, 3, 2, 1}, config.data.toArray());
+    }
+
+    static void validateRecognitionConfig_2_1(
+            android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig config,
+            int captureDevice, int captureHandle) {
+        assertTrue(config.header.captureRequested);
+        assertEquals(captureDevice, config.header.captureDevice);
+        assertEquals(captureHandle, config.header.captureHandle);
+        assertEquals(1, config.header.phrases.size());
+        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra =
+                config.header.phrases.get(0);
+        assertEquals(123, halPhraseExtra.id);
+        assertEquals(4, halPhraseExtra.confidenceLevel);
+        assertEquals(5, halPhraseExtra.recognitionModes);
+        assertEquals(1, halPhraseExtra.levels.size());
+        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0);
+        assertEquals(234, halLevel.userId);
+        assertEquals(34, halLevel.levelPercent);
+        assertArrayEquals(new byte[]{5, 4, 3, 2, 1},
+                HidlMemoryUtil.hidlMemoryToByteArray(config.data));
+    }
+
+    static void validateRecognitionConfig_2_3(
+            android.hardware.soundtrigger.V2_3.RecognitionConfig config, int captureDevice,
+            int captureHandle) {
+        validateRecognitionConfig_2_1(config.base, captureDevice, captureHandle);
+
+        assertEquals(AudioCapabilities.ECHO_CANCELLATION
+                | AudioCapabilities.NOISE_SUPPRESSION, config.audioCapabilities);
+    }
+
+    static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_0(
+            int hwHandle,
+            int status) {
+        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent halEvent =
+                new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent();
+        halEvent.status = status;
+        halEvent.type = SoundModelType.GENERIC;
+        halEvent.model = hwHandle;
+        halEvent.captureAvailable = true;
+        // This field is ignored.
+        halEvent.captureSession = 9999;
+        halEvent.captureDelayMs = 234;
+        halEvent.capturePreambleMs = 345;
+        halEvent.triggerInData = true;
+        halEvent.audioConfig.sampleRateHz = 456;
+        halEvent.audioConfig.channelMask = AudioChannelMask.IN_LEFT;
+        halEvent.audioConfig.format = AudioFormat.MP3;
+        // hwEvent.audioConfig.offloadInfo is irrelevant.
+        halEvent.data.add((byte) 31);
+        halEvent.data.add((byte) 32);
+        halEvent.data.add((byte) 33);
+        return halEvent;
+    }
+
+    static RecognitionEvent createRecognitionEvent(@RecognitionStatus int status) {
+        RecognitionEvent event = new RecognitionEvent();
+        event.status = status;
+        event.type = SoundModelType.GENERIC;
+        event.captureAvailable = true;
+        event.captureDelayMs = 234;
+        event.capturePreambleMs = 345;
+        event.triggerInData = true;
+        event.audioConfig = new AudioConfig();
+        event.audioConfig.sampleRateHz = 456;
+        event.audioConfig.channelMask = AudioChannelMask.IN_LEFT;
+        event.audioConfig.format = AudioFormat.MP3;
+        //event.audioConfig.offloadInfo is irrelevant.
+        event.data = new byte[]{31, 32, 33};
+        return event;
+    }
+
+    static ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1(
+            int hwHandle,
+            int status) {
+        ISoundTriggerHwCallback.RecognitionEvent halEvent =
+                new ISoundTriggerHwCallback.RecognitionEvent();
+        halEvent.header = createRecognitionEvent_2_0(hwHandle, status);
+        halEvent.header.data.clear();
+        halEvent.data = HidlMemoryUtil.byteArrayToHidlMemory(new byte[]{31, 32, 33});
+        return halEvent;
+    }
+
+    static void validateRecognitionEvent(RecognitionEvent event, @RecognitionStatus int status) {
+        assertEquals(status, event.status);
+        assertEquals(SoundModelType.GENERIC, event.type);
+        assertTrue(event.captureAvailable);
+        assertEquals(234, event.captureDelayMs);
+        assertEquals(345, event.capturePreambleMs);
+        assertTrue(event.triggerInData);
+        assertEquals(456, event.audioConfig.sampleRateHz);
+        assertEquals(AudioChannelMask.IN_LEFT, event.audioConfig.channelMask);
+        assertEquals(AudioFormat.MP3, event.audioConfig.format);
+        assertArrayEquals(new byte[]{31, 32, 33}, event.data);
+    }
+
+    static PhraseRecognitionEvent createPhraseRecognitionEvent(@RecognitionStatus int status) {
+        PhraseRecognitionEvent event = new PhraseRecognitionEvent();
+        event.common = createRecognitionEvent(status);
+
+        PhraseRecognitionExtra extra = new PhraseRecognitionExtra();
+        extra.id = 123;
+        extra.confidenceLevel = 52;
+        extra.recognitionModes = RecognitionMode.VOICE_TRIGGER
+                | RecognitionMode.GENERIC_TRIGGER;
+        ConfidenceLevel level = new ConfidenceLevel();
+        level.userId = 31;
+        level.levelPercent = 43;
+        extra.levels = new ConfidenceLevel[]{level};
+        event.phraseExtras = new PhraseRecognitionExtra[]{extra};
+        return event;
+    }
+
+    static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent
+    createPhraseRecognitionEvent_2_0(int hwHandle, int status) {
+        android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent =
+                new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent();
+        halEvent.common = createRecognitionEvent_2_0(hwHandle, status);
+
+        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra =
+                new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra();
+        halExtra.id = 123;
+        halExtra.confidenceLevel = 52;
+        halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER
+                | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER;
+        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel =
+                new android.hardware.soundtrigger.V2_0.ConfidenceLevel();
+        halLevel.userId = 31;
+        halLevel.levelPercent = 43;
+        halExtra.levels.add(halLevel);
+        halEvent.phraseExtras.add(halExtra);
+        return halEvent;
+    }
+
+    static ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_1(
+            int hwHandle, int status) {
+        ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent =
+                new ISoundTriggerHwCallback.PhraseRecognitionEvent();
+        halEvent.common = createRecognitionEvent_2_1(hwHandle, status);
+
+        android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra =
+                new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra();
+        halExtra.id = 123;
+        halExtra.confidenceLevel = 52;
+        halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER
+                | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER;
+        android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel =
+                new android.hardware.soundtrigger.V2_0.ConfidenceLevel();
+        halLevel.userId = 31;
+        halLevel.levelPercent = 43;
+        halExtra.levels.add(halLevel);
+        halEvent.phraseExtras.add(halExtra);
+        return halEvent;
+    }
+
+    static void validatePhraseRecognitionEvent(PhraseRecognitionEvent event,
+            @RecognitionStatus int status) {
+        validateRecognitionEvent(event.common, status);
+
+        assertEquals(1, event.phraseExtras.length);
+        assertEquals(123, event.phraseExtras[0].id);
+        assertEquals(52, event.phraseExtras[0].confidenceLevel);
+        assertEquals(RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER,
+                event.phraseExtras[0].recognitionModes);
+        assertEquals(1, event.phraseExtras[0].levels.length);
+        assertEquals(31, event.phraseExtras[0].levels[0].userId);
+        assertEquals(43, event.phraseExtras[0].levels[0].levelPercent);
+    }
+
+    private static FileDescriptor byteArrayToFileDescriptor(byte[] data) {
+        try {
+            SharedMemory shmem = SharedMemory.create("", data.length);
+            ByteBuffer buffer = shmem.mapReadWrite();
+            buffer.put(data);
+            return shmem.getFileDescriptor();
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
new file mode 100644
index 0000000..65a9759
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Test that the ledger records transactions correctly. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LedgerTest {
+
+    @Test
+    public void testInitialState() {
+        final Ledger ledger = new Ledger();
+        assertEquals(0, ledger.getCurrentBalance());
+        assertEquals(0, ledger.get24HourSum(0, 0));
+    }
+
+    @Test
+    public void testMultipleTransactions() {
+        final Ledger ledger = new Ledger();
+        ledger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 5));
+        assertEquals(5, ledger.getCurrentBalance());
+        assertEquals(5, ledger.get24HourSum(1, 60_000));
+        ledger.recordTransaction(new Ledger.Transaction(2000, 2000, 1, null, 25));
+        assertEquals(30, ledger.getCurrentBalance());
+        assertEquals(30, ledger.get24HourSum(1, 60_000));
+        ledger.recordTransaction(new Ledger.Transaction(5000, 5500, 1, null, -10));
+        assertEquals(20, ledger.getCurrentBalance());
+        assertEquals(20, ledger.get24HourSum(1, 60_000));
+    }
+
+    @Test
+    public void test24HourSum() {
+        final Ledger ledger = new Ledger();
+        ledger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 500));
+        assertEquals(500, ledger.get24HourSum(1, 24 * HOUR_IN_MILLIS));
+        ledger.recordTransaction(
+                new Ledger.Transaction(2 * HOUR_IN_MILLIS, 3 * HOUR_IN_MILLIS, 1, null, 2500));
+        assertEquals(3000, ledger.get24HourSum(1, 24 * HOUR_IN_MILLIS));
+        ledger.recordTransaction(
+                new Ledger.Transaction(4 * HOUR_IN_MILLIS, 4 * HOUR_IN_MILLIS, 1, null, 1));
+        assertEquals(3001, ledger.get24HourSum(1, 24 * HOUR_IN_MILLIS));
+        assertEquals(2501, ledger.get24HourSum(1, 25 * HOUR_IN_MILLIS));
+        assertEquals(2501, ledger.get24HourSum(1, 26 * HOUR_IN_MILLIS));
+        // Pro-rated as the second transaction phases out
+        assertEquals(1251,
+                ledger.get24HourSum(1, 26 * HOUR_IN_MILLIS + 30 * MINUTE_IN_MILLIS));
+        assertEquals(1, ledger.get24HourSum(1, 27 * HOUR_IN_MILLIS));
+        assertEquals(0, ledger.get24HourSum(1, 28 * HOUR_IN_MILLIS));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/tare/OWNERS b/services/tests/servicestests/src/com/android/server/tare/OWNERS
new file mode 100644
index 0000000..217a5ed
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tare/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 8af2c4d0..28838ae 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -97,7 +97,7 @@
 
         try {
             mTimeZoneDetectorService.getCapabilitiesAndConfig();
-            fail();
+            fail("Expected SecurityException");
         } finally {
             verify(mMockContext).enforceCallingPermission(
                     eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
@@ -129,7 +129,7 @@
         ITimeZoneDetectorListener mockListener = mock(ITimeZoneDetectorListener.class);
         try {
             mTimeZoneDetectorService.addListener(mockListener);
-            fail();
+            fail("Expected SecurityException");
         } finally {
             verify(mMockContext).enforceCallingPermission(
                     eq(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION),
@@ -235,7 +235,7 @@
 
         try {
             mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion);
-            fail();
+            fail("Expected SecurityException");
         } finally {
             verify(mMockContext).enforceCallingOrSelfPermission(
                     eq(android.Manifest.permission.SET_TIME_ZONE),
@@ -268,7 +268,7 @@
 
         try {
             mTimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion);
-            fail();
+            fail("Expected SecurityException");
         } finally {
             verify(mMockContext).enforceCallingOrSelfPermission(
                     eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE),
@@ -301,7 +301,7 @@
 
         try {
             mTimeZoneDetectorService.suggestTelephonyTimeZone(timeZoneSuggestion);
-            fail();
+            fail("Expected SecurityException");
         } finally {
             verify(mMockContext).enforceCallingPermission(
                     eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE),
@@ -317,7 +317,7 @@
 
         try {
             mTimeZoneDetectorService.suggestTelephonyTimeZone(timeZoneSuggestion);
-            fail();
+            fail("Expected SecurityException");
         } finally {
             verify(mMockContext).enforceCallingPermission(
                     eq(android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE),
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index aadab6e..2f36c7f 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -365,13 +365,13 @@
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[0], listener, clientId0);
         assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId0[0])
-                .setPriority(clientPriorities[0]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId0[0], clientPriorities[0], 0/*niceValue*/);
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[1], new TestResourcesReclaimListener(), clientId1);
         assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId1[0])
-                .setPriority(clientPriorities[1]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId1[0], clientPriorities[1], 0/*niceValue*/);
 
         // Init frontend resources.
         TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
@@ -415,13 +415,13 @@
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[0], listener, clientId0);
         assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId0[0])
-                .setPriority(clientPriorities[0]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId0[0], clientPriorities[0], 0/*niceValue*/);
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[1], new TestResourcesReclaimListener(), clientId1);
         assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId1[0])
-                .setPriority(clientPriorities[1]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId1[0], clientPriorities[1], 0/*niceValue*/);
 
         // Init frontend resources.
         TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
@@ -511,13 +511,13 @@
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[0], listener, clientId0);
         assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId0[0])
-                .setPriority(clientPriorities[0]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId0[0], clientPriorities[0], 0/*niceValue*/);
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[1], new TestResourcesReclaimListener(), clientId1);
         assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId1[0])
-                .setPriority(clientPriorities[1]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId1[0], clientPriorities[1], 0/*niceValue*/);
 
         // Init cas resources.
         mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
@@ -567,13 +567,13 @@
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[0], listener, clientId0);
         assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId0[0])
-                .setPriority(clientPriorities[0]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId0[0], clientPriorities[0], 0/*niceValue*/);
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[1], new TestResourcesReclaimListener(), clientId1);
         assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId1[0])
-                .setPriority(clientPriorities[1]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId1[0], clientPriorities[1], 0/*niceValue*/);
 
         // Init cicam/cas resources.
         mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
@@ -697,13 +697,13 @@
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[0], listener, clientId0);
         assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId0[0])
-                .setPriority(clientPriorities[0]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId0[0], clientPriorities[0], 0/*niceValue*/);
         mTunerResourceManagerService.registerClientProfileInternal(
                 profiles[1], new TestResourcesReclaimListener(), clientId1);
         assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
-        mTunerResourceManagerService.getClientProfile(clientId1[0])
-                .setPriority(clientPriorities[1]);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                clientId1[0], clientPriorities[1], 0/*niceValue*/);
 
         // Init lnb resources.
         int[] lnbHandles = {1};
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
index b11c85c0..c611e38 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
+++ b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
@@ -74,3 +74,17 @@
     resource_dirs: ["res"],
     manifest: "AndroidManifestApp4.xml",
 }
+
+android_test_helper_app {
+    name: "PackageParserTestApp5",
+    sdk_version: "current",
+    srcs: ["**/*.java"],
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    resource_dirs: ["res"],
+    manifest: "AndroidManifestApp5.xml",
+}
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp5.xml b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp5.xml
new file mode 100644
index 0000000..cc6caad
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp5.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.servicestests.apps.packageparserapp" >
+
+    <uses-sdk android:minSdkVersion="3"
+              android:targetSdkVersion="3" />
+
+    <application>
+        <activity android:name=".TestActivity"
+                  android:exported="true" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
index fd68046..0169a7d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
@@ -16,10 +16,13 @@
 
 package com.android.server.notification;
 
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -116,4 +119,15 @@
                 SmallHash.hash(group.hashCode()),
                 p.getGroupIdHash());
     }
+
+    @Test
+    public void testIsForegroundService() {
+        NotificationRecordLogger.NotificationRecordPair p = getNotificationRecordPair(
+                0, null);
+        assertFalse(NotificationRecordLogger.isForegroundService(p.r));
+
+        // Set foreground service
+        p.r.getSbn().getNotification().flags |= FLAG_FOREGROUND_SERVICE;
+        assertTrue(NotificationRecordLogger.isForegroundService(p.r));
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 1116204..9ad007d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -36,6 +36,7 @@
 
 import java.util.Calendar;
 import java.util.GregorianCalendar;
+import java.util.TimeZone;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -171,6 +172,119 @@
     }
 
     @Test
+    public void testGetNextChangeTime_startTomorrowInDaylight() {
+        // Test that the correct thing happens when the next start time would be tomorrow, during
+        // a schedule start time that doesn't exist that day. Consistent with "start times" as
+        // implemented in isInSchedule, this should get adjusted to the closest actual time.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // "today" = the day before the skipped hour for daylight savings.
+        Calendar today = getDaylightSavingsForwardDay();
+        today.set(Calendar.HOUR_OF_DAY, 23);
+        today.set(Calendar.MINUTE, 15);
+        Calendar tomorrow = getDaylightSavingsForwardDay();
+        tomorrow.add(Calendar.DATE, 1);
+        mScheduleInfo.days = new int[] {today.get(Calendar.DAY_OF_WEEK),
+                tomorrow.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 2;
+        mScheduleInfo.endHour = 4;
+        mScheduleInfo.startMinute = 15;
+        mScheduleInfo.endMinute = 15;
+        mScheduleInfo.exitAtAlarm = false;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // The expected next change time should be tomorrow, 3AM as 2:15AM doesn't exist.
+        Calendar expected = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
+        expected.setTimeInMillis(tomorrow.getTimeInMillis());
+        expected.set(Calendar.HOUR_OF_DAY, 3);
+        expected.set(Calendar.MINUTE, 0);
+        expected.set(Calendar.SECOND, 0);
+        expected.set(Calendar.MILLISECOND, 0);
+
+        long actualMs = mScheduleCalendar.getNextChangeTime(today.getTimeInMillis());
+        GregorianCalendar actual = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
+        actual.setTimeInMillis(actualMs);
+        assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+                actualMs);
+    }
+
+    @Test
+    public void testGetNextChangeTime_startTomorrowWhenTodayIsDaylight() {
+        // Test that the correct thing happens when the next start time would be tomorrow, but
+        // today is the day when daylight time switches over (so the "schedule start time" today
+        // may not exist).
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // "today" = the day with the skipped hour for daylight savings.
+        Calendar today = getDaylightSavingsForwardDay();
+        today.add(Calendar.DATE, 1);
+        today.set(Calendar.HOUR_OF_DAY, 23);
+        today.set(Calendar.MINUTE, 15);
+        Calendar tomorrow = getDaylightSavingsForwardDay();
+        tomorrow.add(Calendar.DATE, 2);
+        mScheduleInfo.days = new int[] {today.get(Calendar.DAY_OF_WEEK),
+                tomorrow.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 2;
+        mScheduleInfo.endHour = 4;
+        mScheduleInfo.startMinute = 15;
+        mScheduleInfo.endMinute = 15;
+        mScheduleInfo.exitAtAlarm = false;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // The expected next change time should be tomorrow, 2:15AM.
+        Calendar expected = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
+        expected.setTimeInMillis(tomorrow.getTimeInMillis());
+        expected.set(Calendar.HOUR_OF_DAY, mScheduleInfo.startHour);
+        expected.set(Calendar.MINUTE, mScheduleInfo.startMinute);
+        expected.set(Calendar.SECOND, 0);
+        expected.set(Calendar.MILLISECOND, 0);
+
+        long actualMs = mScheduleCalendar.getNextChangeTime(today.getTimeInMillis());
+        GregorianCalendar actual = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
+        actual.setTimeInMillis(actualMs);
+        assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+                actualMs);
+    }
+
+    @Test
+    public void testGetNextChangeTime_startTomorrowWhenTodayIsDaylightBackward() {
+        // Test that the correct thing happens when the next start time would be tomorrow, but
+        // today is the day when clocks are adjusted backwards (so the "schedule start time" today
+        // exists twice).
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // "today" = the day with the extra hour for daylight savings.
+        Calendar today = getDaylightSavingsBackwardDay();
+        today.add(Calendar.DATE, 1);
+        today.set(Calendar.HOUR_OF_DAY, 23);
+        today.set(Calendar.MINUTE, 15);
+        Calendar tomorrow = getDaylightSavingsBackwardDay();
+        tomorrow.add(Calendar.DATE, 2);
+        mScheduleInfo.days = new int[] {today.get(Calendar.DAY_OF_WEEK),
+                tomorrow.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 1;
+        mScheduleInfo.endHour = 4;
+        mScheduleInfo.startMinute = 15;
+        mScheduleInfo.endMinute = 15;
+        mScheduleInfo.exitAtAlarm = false;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // The expected next change time should be tomorrow, 1:15AM.
+        Calendar expected = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
+        expected.setTimeInMillis(tomorrow.getTimeInMillis());
+        expected.set(Calendar.HOUR_OF_DAY, mScheduleInfo.startHour);
+        expected.set(Calendar.MINUTE, mScheduleInfo.startMinute);
+        expected.set(Calendar.SECOND, 0);
+        expected.set(Calendar.MILLISECOND, 0);
+
+        long actualMs = mScheduleCalendar.getNextChangeTime(today.getTimeInMillis());
+        GregorianCalendar actual = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
+        actual.setTimeInMillis(actualMs);
+        assertEquals("Expected " + expected + " was " + actual, expected.getTimeInMillis(),
+                actualMs);
+    }
+
+    @Test
     public void testShouldExitForAlarm_settingOff() {
         mScheduleInfo.exitAtAlarm = false;
         mScheduleInfo.nextAlarm = 1000;
@@ -416,22 +530,264 @@
     }
 
     @Test
+    public void testIsInSchedule_daylightSavingsForward_startDuringChange() {
+        // Test that if the start time of a ScheduleCalendar is during the nonexistent
+        // hour of daylight savings forward time, the evaluation of whether a time is in the
+        // schedule still works.
+
+        // Set timezone to make sure we're evaluating the correct days.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // Set up schedule for 2:30AM - 4:00AM.
+        final Calendar dstYesterday = getDaylightSavingsForwardDay();
+        final Calendar dstToday = getDaylightSavingsForwardDay();
+        dstToday.add(Calendar.DATE, 1);
+        mScheduleInfo.days = new int[] {dstYesterday.get(Calendar.DAY_OF_WEEK),
+                dstToday.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 2;
+        mScheduleInfo.startMinute = 30;
+        mScheduleInfo.endHour = 4;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // Test cases: there are 2 "on" periods. These cover: before the first schedule
+        // (1AM previous day), during the first schedule (2:30AM), two between the two schedules
+        // (one on each calendar day), during the second (3:30AM), and after the second (4:30AM)
+        Calendar out1 = getDaylightSavingsForwardDay();
+        out1.set(Calendar.HOUR_OF_DAY, 1);
+        out1.set(Calendar.MINUTE, 00);
+        out1.set(Calendar.SECOND, 0);
+        out1.set(Calendar.MILLISECOND, 0);
+
+        Calendar in1 = getDaylightSavingsForwardDay();
+        in1.set(Calendar.HOUR_OF_DAY, 2);
+        in1.set(Calendar.MINUTE, 45);
+        in1.set(Calendar.SECOND, 0);
+        in1.set(Calendar.MILLISECOND, 0);
+
+        Calendar midOut1 = getDaylightSavingsForwardDay();
+        midOut1.set(Calendar.HOUR_OF_DAY, 7);
+        midOut1.set(Calendar.MINUTE, 30);
+        midOut1.set(Calendar.SECOND, 0);
+        midOut1.set(Calendar.MILLISECOND, 0);
+
+        Calendar midOut2 = getDaylightSavingsForwardDay();
+        midOut2.add(Calendar.DATE, 1);
+        midOut2.set(Calendar.HOUR_OF_DAY, 1);
+        midOut2.set(Calendar.MINUTE, 30);
+        midOut2.set(Calendar.SECOND, 0);
+        midOut2.set(Calendar.MILLISECOND, 0);
+
+        // Question: should 3:15AM be in the 2:30-4 schedule on a day when 2:30-3 doesn't exist?
+        Calendar in2 = getDaylightSavingsForwardDay();
+        in2.add(Calendar.DATE, 1);
+        in2.set(Calendar.HOUR_OF_DAY, 3);
+        in2.set(Calendar.MINUTE, 30);
+        in2.set(Calendar.SECOND, 0);
+        in2.set(Calendar.MILLISECOND, 0);
+
+        Calendar out2 = getDaylightSavingsForwardDay();
+        out2.add(Calendar.DATE, 1);
+        out2.set(Calendar.HOUR_OF_DAY, 4);
+        out2.set(Calendar.MINUTE, 30);
+        out2.set(Calendar.SECOND, 0);
+        out2.set(Calendar.MILLISECOND, 0);
+
+        assertFalse(mScheduleCalendar.isInSchedule(out1.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(in1.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(midOut1.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(midOut2.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(in2.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(out2.getTimeInMillis()));
+    }
+
+    @Test
+    public void testIsInSchedule_daylightSavingsForward_endDuringChange() {
+        // Test that if the end time of a ScheduleCalendar is during the nonexistent
+        // hour of daylight savings forward time, the evaluation of whether a time is in the
+        // schedule still works.
+
+        // Set timezone to make sure we're evaluating the correct days.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // Set up schedule for 11:00PM - 2:30AM. On the day when 2AM doesn't exist, this should
+        // effectively finish at 3:30AM(?)
+        final Calendar dstYesterday = getDaylightSavingsForwardDay();
+        final Calendar dstToday = getDaylightSavingsForwardDay();
+        dstToday.add(Calendar.DATE, 1);
+        mScheduleInfo.days = new int[] {dstYesterday.get(Calendar.DAY_OF_WEEK),
+                dstToday.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 23;
+        mScheduleInfo.endHour = 2;
+        mScheduleInfo.endMinute = 30;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // Test cases: before the time period on the previous day; during the time period when
+        // the calendar day is still the previous day; during the time period when the calendar
+        // day is the change day; afterwards.
+        Calendar out1 = getDaylightSavingsForwardDay();
+        out1.set(Calendar.HOUR_OF_DAY, 22);
+        out1.set(Calendar.MINUTE, 00);
+        out1.set(Calendar.SECOND, 0);
+        out1.set(Calendar.MILLISECOND, 0);
+
+        Calendar in1 = getDaylightSavingsForwardDay();
+        in1.set(Calendar.HOUR_OF_DAY, 23);
+        in1.set(Calendar.MINUTE, 30);
+        in1.set(Calendar.SECOND, 0);
+        in1.set(Calendar.MILLISECOND, 0);
+
+        Calendar in2 = getDaylightSavingsForwardDay();
+        in2.add(Calendar.DATE, 1);
+        in2.set(Calendar.HOUR_OF_DAY, 1);
+        in2.set(Calendar.MINUTE, 30);
+        in2.set(Calendar.SECOND, 0);
+        in2.set(Calendar.MILLISECOND, 0);
+
+        // Question: Should 3:15AM be out of the schedule on a day when 2-3 doesn't exist?
+        Calendar out2 = getDaylightSavingsForwardDay();
+        out2.add(Calendar.DATE, 1);
+        out2.set(Calendar.HOUR_OF_DAY, 3);
+        out2.set(Calendar.MINUTE, 45);
+        out2.set(Calendar.SECOND, 0);
+        out2.set(Calendar.MILLISECOND, 0);
+
+        assertFalse(mScheduleCalendar.isInSchedule(out1.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(in1.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(in2.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(out2.getTimeInMillis()));
+    }
+
+    @Test
+    public void testIsInSchedule_daylightSavingsBackward_startDuringChange() {
+        // Test that if the start time of a ScheduleCalendar is during the duplicated
+        // hour of daylight savings backward time, the evaluation of whether a time is in the
+        // schedule still works. It's not clear what correct behavior is during the duplicated
+        // 1:00->1:59->1:00->1:59 time period, but times outside that should still work.
+
+        // Set timezone to make sure we're evaluating the correct days.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // Set up schedule for 1:15AM - 4:00AM.
+        final Calendar dstYesterday = getDaylightSavingsBackwardDay();
+        final Calendar dstToday = getDaylightSavingsBackwardDay();
+        dstToday.add(Calendar.DATE, 1);
+        mScheduleInfo.days = new int[] {dstYesterday.get(Calendar.DAY_OF_WEEK),
+                dstToday.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 1;
+        mScheduleInfo.startMinute = 15;
+        mScheduleInfo.endHour = 4;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // Test cases: there are 2 "on" periods. These cover: before the first schedule
+        // (1AM previous day), during the first schedule (2:30AM), two between the two schedules
+        // (one on each calendar day), during the second (2:30AM), and after the second (4:30AM)
+        Calendar out1 = getDaylightSavingsBackwardDay();
+        out1.set(Calendar.HOUR_OF_DAY, 1);
+        out1.set(Calendar.MINUTE, 00);
+        out1.set(Calendar.SECOND, 0);
+        out1.set(Calendar.MILLISECOND, 0);
+
+        Calendar in1 = getDaylightSavingsBackwardDay();
+        in1.set(Calendar.HOUR_OF_DAY, 2);
+        in1.set(Calendar.MINUTE, 30);
+        in1.set(Calendar.SECOND, 0);
+        in1.set(Calendar.MILLISECOND, 0);
+
+        Calendar midOut1 = getDaylightSavingsBackwardDay();
+        midOut1.set(Calendar.HOUR_OF_DAY, 7);
+        midOut1.set(Calendar.MINUTE, 30);
+        midOut1.set(Calendar.SECOND, 0);
+        midOut1.set(Calendar.MILLISECOND, 0);
+
+        Calendar midOut2 = getDaylightSavingsBackwardDay();
+        midOut2.add(Calendar.DATE, 1);
+        midOut2.set(Calendar.HOUR_OF_DAY, 0);
+        midOut2.set(Calendar.MINUTE, 30);
+        midOut2.set(Calendar.SECOND, 0);
+        midOut2.set(Calendar.MILLISECOND, 0);
+
+        Calendar in2 = getDaylightSavingsBackwardDay();
+        in2.add(Calendar.DATE, 1);
+        in2.set(Calendar.HOUR_OF_DAY, 2);
+        in2.set(Calendar.MINUTE, 30);
+        in2.set(Calendar.SECOND, 0);
+        in2.set(Calendar.MILLISECOND, 0);
+
+        Calendar out2 = getDaylightSavingsBackwardDay();
+        out2.add(Calendar.DATE, 1);
+        out2.set(Calendar.HOUR_OF_DAY, 4);
+        out2.set(Calendar.MINUTE, 30);
+        out2.set(Calendar.SECOND, 0);
+        out2.set(Calendar.MILLISECOND, 0);
+
+        assertFalse(mScheduleCalendar.isInSchedule(out1.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(in1.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(midOut1.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(midOut2.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(in2.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(out2.getTimeInMillis()));
+    }
+
+    @Test
+    public void testIsInSchedule_daylightSavings_flippedSchedule() {
+        // This test is for the unlikely edge case where the skipped hour due to daylight savings
+        // causes the evaluated start time to be "later" than the schedule's end time on that day,
+        // for instance if the schedule is 2:30AM-3:15AM; 2:30AM may evaluate to 3:30AM on the day
+        // of daylight change.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+
+        // Set up schedule for 2:30AM - 3:15AM.
+        final Calendar dstYesterday = getDaylightSavingsForwardDay();
+        final Calendar dstToday = getDaylightSavingsForwardDay();
+        dstToday.add(Calendar.DATE, 1);
+        mScheduleInfo.days = new int[] {dstYesterday.get(Calendar.DAY_OF_WEEK),
+                dstToday.get(Calendar.DAY_OF_WEEK)};
+        mScheduleInfo.startHour = 2;
+        mScheduleInfo.startMinute = 30;
+        mScheduleInfo.endHour = 3;
+        mScheduleInfo.endMinute = 15;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        // It may not be well-defined what times around the 2-3AM range one might expect to be
+        // included or not included on the weird day when 2AM doesn't exist, but other unrelated
+        // times of day (here, 3PM) should definitely be out.
+        Calendar out1 = getDaylightSavingsForwardDay();
+        out1.set(Calendar.HOUR_OF_DAY, 15);
+        out1.set(Calendar.MINUTE, 0);
+        out1.set(Calendar.SECOND, 0);
+        out1.set(Calendar.MILLISECOND, 0);
+
+        Calendar out2 = getDaylightSavingsForwardDay();
+        out2.add(Calendar.DATE, 1);
+        out2.set(Calendar.HOUR_OF_DAY, 15);
+        out2.set(Calendar.MINUTE, 0);
+        out2.set(Calendar.SECOND, 0);
+        out2.set(Calendar.MILLISECOND, 0);
+
+        assertFalse(mScheduleCalendar.isInSchedule(out1.getTimeInMillis()));
+        assertFalse(mScheduleCalendar.isInSchedule(out2.getTimeInMillis()));
+    }
+
+    @Test
     public void testIsAlarmInSchedule_alarmAndNowInSchedule_sameScheduleTrigger_daylightSavings() {
-        Calendar alarm = getDaylightSavingsDay();
+        // Need to set the time zone explicitly to a US one so that the daylight savings time day is
+        // correct.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+        Calendar alarm = getDaylightSavingsForwardDay();
         alarm.set(Calendar.HOUR_OF_DAY, 23);
         alarm.set(Calendar.MINUTE, 15);
         alarm.set(Calendar.SECOND, 0);
         alarm.set(Calendar.MILLISECOND, 0);
 
-        Calendar now = getDaylightSavingsDay();
+        Calendar now = getDaylightSavingsForwardDay();
         now.set(Calendar.HOUR_OF_DAY, 2);
         now.set(Calendar.MINUTE, 10);
         now.set(Calendar.SECOND, 0);
         now.set(Calendar.MILLISECOND, 0);
         now.add(Calendar.DATE, 1); // add a day, on daylight savings this becomes 3:10am
 
-        final Calendar tempToday = getDaylightSavingsDay();
-        final Calendar tempTomorrow = getDaylightSavingsDay();
+        final Calendar tempToday = getDaylightSavingsForwardDay();
+        final Calendar tempTomorrow = getDaylightSavingsForwardDay();
         tempTomorrow.add(Calendar.DATE, 1);
         mScheduleInfo.days = new int[] {tempToday.get(Calendar.DAY_OF_WEEK),
                 tempTomorrow.get(Calendar.DAY_OF_WEEK)};
@@ -506,6 +862,80 @@
                 now.getTimeInMillis()));
     }
 
+    @Test
+    public void testClosestActualTime_regularTimesAndSkippedTime() {
+        // Make sure we're operating in the relevant time zone for the assumed Daylight Savings day
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
+        Calendar day = getDaylightSavingsForwardDay();
+        day.set(Calendar.HOUR_OF_DAY, 15);
+        day.set(Calendar.MINUTE, 25);
+        day.set(Calendar.SECOND, 0);
+        day.set(Calendar.MILLISECOND, 0);
+        assertEquals(day.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(day.getTimeInMillis(), 15, 25));
+
+        // Check a skipped time
+        day.add(Calendar.DATE, 1);
+        day.set(Calendar.HOUR_OF_DAY, 3);
+        day.set(Calendar.MINUTE, 0);
+        day.set(Calendar.SECOND, 0);
+        day.set(Calendar.MILLISECOND, 0);
+        assertEquals(day.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(day.getTimeInMillis(), 2, 15));
+
+        // Check a non-skipped time after the clocks have moved forward
+        day.set(Calendar.HOUR_OF_DAY, 15);
+        day.set(Calendar.MINUTE, 25);
+        day.set(Calendar.SECOND, 0);
+        day.set(Calendar.MILLISECOND, 0);
+        assertEquals(day.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(day.getTimeInMillis(), 15, 25));
+    }
+
+    @Test
+    public void testClosestActualTime_otherTimeZones() {
+        // Make sure this doesn't only work for US/Eastern time.
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("Europe/London"));
+        Calendar ukDstDay = new GregorianCalendar(TimeZone.getTimeZone("Europe/London"));
+        ukDstDay.set(2021, Calendar.MARCH, 28);
+
+        // Check a skipped time, which is 01:xx on that day in the UK
+        ukDstDay.set(Calendar.HOUR_OF_DAY, 2);
+        ukDstDay.set(Calendar.MINUTE, 0);
+        ukDstDay.set(Calendar.SECOND, 0);
+        ukDstDay.set(Calendar.MILLISECOND, 0);
+        assertEquals(ukDstDay.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(ukDstDay.getTimeInMillis(), 1, 25));
+
+        // Check a non-skipped time
+        ukDstDay.set(Calendar.HOUR_OF_DAY, 11);
+        ukDstDay.set(Calendar.MINUTE, 23);
+        ukDstDay.set(Calendar.SECOND, 0);
+        ukDstDay.set(Calendar.MILLISECOND, 0);
+        assertEquals(ukDstDay.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(ukDstDay.getTimeInMillis(), 11, 23));
+
+        mScheduleCalendar.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
+        Calendar frDstDay = new GregorianCalendar(TimeZone.getTimeZone("Europe/Paris"));
+        frDstDay.set(2021, Calendar.MARCH, 28);
+
+        // Check a skipped time, which is 02:xx on that day in France
+        frDstDay.set(Calendar.HOUR_OF_DAY, 3);
+        frDstDay.set(Calendar.MINUTE, 0);
+        frDstDay.set(Calendar.SECOND, 0);
+        frDstDay.set(Calendar.MILLISECOND, 0);
+        assertEquals(frDstDay.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(frDstDay.getTimeInMillis(), 2, 25));
+
+        // Check a regular time
+        frDstDay.set(Calendar.HOUR_OF_DAY, 14);
+        frDstDay.set(Calendar.MINUTE, 59);
+        frDstDay.set(Calendar.SECOND, 0);
+        frDstDay.set(Calendar.MILLISECOND, 0);
+        assertEquals(frDstDay.getTimeInMillis(),
+                mScheduleCalendar.getClosestActualTime(frDstDay.getTimeInMillis(), 14, 59));
+    }
+
     private int getTodayDay() {
         return new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
     }
@@ -517,9 +947,23 @@
     }
 
 
-    private Calendar getDaylightSavingsDay() {
-        // the day before daylight savings in the US - March 9, 2019
-        Calendar daylightSavingsDay = new GregorianCalendar(2019, 2, 9);
+    private Calendar getDaylightSavingsForwardDay() {
+        // the day before daylight savings rolls forward in the US - March 9, 2019
+        // 2AM March 10, 2019 does not exist -- goes straight from 1:59 to 3:00
+        // Specifically set to US/Eastern time zone rather than relying on a default time zone
+        // to make sure the date is the correct one, since DST changes vary by region.
+        Calendar daylightSavingsDay = new GregorianCalendar(
+                TimeZone.getTimeZone("America/New_York"));
+        daylightSavingsDay.set(2019, Calendar.MARCH, 9);
+        return daylightSavingsDay;
+    }
+
+    private Calendar getDaylightSavingsBackwardDay() {
+        // the day before daylight savings rolls backward in the US - November 2, 2019
+        // In this instance, 1AM November 3 2019 is repeated twice; 1:00->1:59->1:00->1:59->2:00
+        Calendar daylightSavingsDay = new GregorianCalendar(
+                TimeZone.getTimeZone("America/New_York"));
+        daylightSavingsDay.set(2019, Calendar.NOVEMBER, 2);
         return daylightSavingsDay;
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 32a4774..697d102 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -260,7 +260,7 @@
         notifyActivityLaunching(mTopActivity.intent);
         notifyActivityLaunched(START_SUCCESS, mTopActivity);
         doReturn(true).when(mTopActivity.mDisplayContent).isSleeping();
-        mTopActivity.setState(Task.ActivityState.RESUMED, "test");
+        mTopActivity.setState(ActivityRecord.State.RESUMED, "test");
         mTopActivity.setVisibility(false);
         waitHandlerIdle(mAtm.mH);
         // Not cancel immediately because in one of real cases, the keyguard may be going away or
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 b7713a9..0409a8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -65,19 +65,19 @@
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
-import static com.android.server.wm.Task.ActivityState.DESTROYED;
-import static com.android.server.wm.Task.ActivityState.DESTROYING;
-import static com.android.server.wm.Task.ActivityState.FINISHING;
-import static com.android.server.wm.Task.ActivityState.INITIALIZING;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.ActivityState.STARTED;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.ActivityRecord.State.DESTROYED;
+import static com.android.server.wm.ActivityRecord.State.DESTROYING;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
+import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STARTED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
@@ -133,7 +133,7 @@
 import androidx.test.filters.MediumTest;
 
 import com.android.internal.R;
-import com.android.server.wm.Task.ActivityState;
+import com.android.server.wm.ActivityRecord.State;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -340,7 +340,7 @@
     public void testSetsRelaunchReason_NotDragResizing() {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.RESUMED, "Testing");
+        activity.setState(RESUMED, "Testing");
 
         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
@@ -365,7 +365,7 @@
     public void testSetsRelaunchReason_DragResizing() {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.RESUMED, "Testing");
+        activity.setState(RESUMED, "Testing");
 
         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
@@ -392,7 +392,7 @@
     public void testRelaunchClearTopWaitingTranslucent() {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.RESUMED, "Testing");
+        activity.setState(RESUMED, "Testing");
 
         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
@@ -413,7 +413,7 @@
     public void testSetsRelaunchReason_NonResizeConfigChanges() {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.RESUMED, "Testing");
+        activity.setState(RESUMED, "Testing");
 
         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
@@ -461,7 +461,7 @@
                 .setCreateTask(true)
                 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
                 .build();
-        activity.setState(Task.ActivityState.RESUMED, "Testing");
+        activity.setState(RESUMED, "Testing");
 
         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
                 activity.getConfiguration()));
@@ -624,7 +624,7 @@
     @Test
     public void testShouldMakeActive_deferredResume() {
         final ActivityRecord activity = createActivityWithTask();
-        activity.setState(Task.ActivityState.STOPPED, "Testing");
+        activity.setState(STOPPED, "Testing");
 
         mSupervisor.beginDeferResume();
         assertEquals(false, activity.shouldMakeActive(null /* activeActivity */));
@@ -640,7 +640,7 @@
         ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(task).build();
         finishingActivity.finishing = true;
         ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
-        activity.setState(Task.ActivityState.STOPPED, "Testing");
+        activity.setState(STOPPED, "Testing");
 
         assertEquals(false, activity.shouldMakeActive(null /* activeActivity */));
     }
@@ -649,15 +649,16 @@
     public void testShouldResume_stackVisibility() {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.STOPPED, "Testing");
+        activity.setState(STOPPED, "Testing");
 
-        doReturn(TASK_VISIBILITY_VISIBLE).when(task).getVisibility(null);
+        doReturn(TASK_FRAGMENT_VISIBILITY_VISIBLE).when(task).getVisibility(null);
         assertEquals(true, activity.shouldResumeActivity(null /* activeActivity */));
 
-        doReturn(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(task).getVisibility(null);
+        doReturn(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT)
+                .when(task).getVisibility(null);
         assertEquals(false, activity.shouldResumeActivity(null /* activeActivity */));
 
-        doReturn(TASK_VISIBILITY_INVISIBLE).when(task).getVisibility(null);
+        doReturn(TASK_FRAGMENT_VISIBILITY_INVISIBLE).when(task).getVisibility(null);
         assertEquals(false, activity.shouldResumeActivity(null /* activeActivity */));
     }
 
@@ -665,13 +666,13 @@
     public void testShouldResumeOrPauseWithResults() {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.STOPPED, "Testing");
+        activity.setState(STOPPED, "Testing");
 
         ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
         activity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
         topActivity.finishing = true;
 
-        doReturn(TASK_VISIBILITY_VISIBLE).when(task).getVisibility(null);
+        doReturn(TASK_FRAGMENT_VISIBILITY_VISIBLE).when(task).getVisibility(null);
         assertEquals(true, activity.shouldResumeActivity(null /* activeActivity */));
         assertEquals(false, activity.shouldPauseActivity(null /*activeActivity */));
     }
@@ -684,7 +685,7 @@
                 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
                 .build();
         final Task task = activity.getTask();
-        activity.setState(Task.ActivityState.STOPPED, "Testing");
+        activity.setState(STOPPED, "Testing");
 
         final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         try {
@@ -727,7 +728,7 @@
         final ActivityRecord activity = createActivityWithTask();
         ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(activity.getTask()).build();
         topActivity.setOccludesParent(false);
-        activity.setState(Task.ActivityState.STOPPED, "Testing");
+        activity.setState(STOPPED, "Testing");
         activity.setVisibility(true);
         activity.makeActiveIfNeeded(null /* activeActivity */);
         assertEquals(STARTED, activity.getState());
@@ -1011,8 +1012,8 @@
     @Test
     public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
         final ActivityRecord activity = createActivityWithTask();
-        final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
-        for (ActivityState state : states) {
+        final State[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
+        for (State state : states) {
             activity.finishing = false;
             activity.setState(state, "test");
             reset(activity);
@@ -1393,7 +1394,7 @@
     }
 
     private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask,
-            ActivityState secondActivityState) {
+            State secondActivityState) {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
         final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -1903,8 +1904,7 @@
         assertTrue(wpc.registeredForActivityConfigChanges());
 
         // Create a new task with custom config to reparent the activity to.
-        final Task newTask =
-                new TaskBuilder(mSupervisor).setParentTask(initialTask.getRootTask()).build();
+        final Task newTask = new TaskBuilder(mSupervisor).build();
         final Configuration newConfig = newTask.getConfiguration();
         newConfig.densityDpi += 100;
         newTask.onRequestedOverrideConfigurationChanged(newConfig);
@@ -1936,8 +1936,7 @@
                 .diff(wpc.getRequestedOverrideConfiguration()));
 
         // Create a new task with custom config to reparent the second activity to.
-        final Task newTask =
-                new TaskBuilder(mSupervisor).setParentTask(initialTask.getRootTask()).build();
+        final Task newTask = new TaskBuilder(mSupervisor).build();
         final Configuration newConfig = newTask.getConfiguration();
         newConfig.densityDpi += 100;
         newTask.onRequestedOverrideConfigurationChanged(newConfig);
@@ -2147,7 +2146,7 @@
         assertFalse(activity.supportsPictureInPicture());
     }
 
-    private void verifyProcessInfoUpdate(ActivityRecord activity, ActivityState state,
+    private void verifyProcessInfoUpdate(ActivityRecord activity, State state,
             boolean shouldUpdate, boolean activityChange) {
         reset(activity.app);
         activity.setState(state, "test");
@@ -2700,6 +2699,40 @@
     }
 
     @Test
+    public void testCloseToSquareFixedOrientationPortrait() {
+        // create a square display
+        final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
+                .setSystemDecorations(true).build();
+        final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
+
+        // create a fixed portrait activity
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).build();
+
+        // check that both the configuration and app bounds are portrait
+        assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
+        assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
+                <= activity.getConfiguration().windowConfiguration.getAppBounds().height());
+    }
+
+    @Test
+    public void testCloseToSquareFixedOrientationLandscape() {
+        // create a square display
+        final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
+                .setSystemDecorations(true).build();
+        final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
+
+        // create a fixed landscape activity
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+                .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE).build();
+
+        // check that both the configuration and app bounds are landscape
+        assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
+        assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
+                > activity.getConfiguration().windowConfiguration.getAppBounds().height());
+    }
+
+    @Test
     public void testSetVisibility_visibleToVisible() {
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setCreateTask(true).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 741f33f..8ca14bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -26,6 +26,10 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -244,7 +248,7 @@
                 .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask())
                 .build();
         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
-        activity.setState(Task.ActivityState.RESUMED, "test");
+        activity.setState(RESUMED, "test");
         mSupervisor.endDeferResume();
 
         assertEquals(activity.app, mAtm.mInternal.getTopApp());
@@ -254,13 +258,13 @@
         activity.mVisibleRequested = false;
         activity.setVisible(false);
         activity.getTask().setPausingActivity(activity);
-        homeActivity.setState(Task.ActivityState.PAUSED, "test");
+        homeActivity.setState(PAUSED, "test");
 
         // Even the visibility states are invisible, the next activity should be resumed because
         // the crashed activity was pausing.
         mAtm.mInternal.handleAppDied(activity.app, false /* restarting */,
                 null /* finishInstrumentationCallback */);
-        assertEquals(Task.ActivityState.RESUMED, homeActivity.getState());
+        assertEquals(RESUMED, homeActivity.getState());
         assertEquals(homeActivity.app, mAtm.mInternal.getTopApp());
     }
 
@@ -271,7 +275,7 @@
         final Task rootHomeTask = mWm.mRoot.getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
         final ActivityRecord homeActivity = new ActivityBuilder(mAtm).setTask(rootHomeTask).build();
         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
-        topActivity.setState(Task.ActivityState.RESUMED, "test");
+        topActivity.setState(RESUMED, "test");
 
         final Consumer<ActivityRecord> assertTopNonSleeping = activity -> {
             assertFalse(mAtm.mInternal.isSleeping());
@@ -287,7 +291,7 @@
         verify(mSupervisor.mGoingToSleepWakeLock).acquire();
         doReturn(true).when(mSupervisor.mGoingToSleepWakeLock).isHeld();
 
-        assertEquals(Task.ActivityState.PAUSING, topActivity.getState());
+        assertEquals(PAUSING, topActivity.getState());
         assertTrue(mAtm.mInternal.isSleeping());
         assertEquals(ActivityManager.PROCESS_STATE_TOP_SLEEPING,
                 mAtm.mInternal.getTopProcessState());
@@ -298,7 +302,7 @@
         final Task topRootTask = topActivity.getRootTask();
         doReturn(true).when(rootHomeTask).goToSleepIfPossible(anyBoolean());
         doReturn(true).when(topRootTask).goToSleepIfPossible(anyBoolean());
-        topActivity.setState(Task.ActivityState.STOPPING, "test");
+        topActivity.setState(STOPPING, "test");
         topActivity.activityStopped(null /* newIcicle */, null /* newPersistentState */,
                 null /* description */);
         verify(mSupervisor.mGoingToSleepWakeLock).release();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 31d4612..af21e02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -35,10 +35,10 @@
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
+import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
 
 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
 import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
-import static com.android.server.wm.DisplayAreaPolicyBuilder.KEY_ROOT_DISPLAY_AREA_ID;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index d5628fc..c4faaa3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -61,6 +61,7 @@
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
+import android.window.DisplayAreaInfo;
 import android.window.IDisplayAreaOrganizer;
 
 import com.google.android.collect.Lists;
@@ -566,6 +567,31 @@
                 .onDisplayAreaVanished(mockDisplayAreaOrganizer, displayArea);
     }
 
+    @Test
+    public void testGetDisplayAreaInfo() {
+        final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(
+                mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST);
+        mDisplayContent.addChild(displayArea, 0);
+        final DisplayAreaInfo info = displayArea.getDisplayAreaInfo();
+
+        assertThat(info.token).isEqualTo(displayArea.mRemoteToken.toWindowContainerToken());
+        assertThat(info.configuration).isEqualTo(displayArea.getConfiguration());
+        assertThat(info.displayId).isEqualTo(mDisplayContent.getDisplayId());
+        assertThat(info.featureId).isEqualTo(displayArea.mFeatureId);
+        assertThat(info.rootDisplayAreaId).isEqualTo(mDisplayContent.mFeatureId);
+
+        final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
+        final int tdaIndex = tda.getParent().mChildren.indexOf(tda);
+        final RootDisplayArea root =
+                new DisplayAreaGroup(mWm, "TestRoot", FEATURE_VENDOR_FIRST + 1);
+        mDisplayContent.addChild(root, tdaIndex + 1);
+        displayArea.reparent(root, 0);
+
+        final DisplayAreaInfo info2 = displayArea.getDisplayAreaInfo();
+
+        assertThat(info2.rootDisplayAreaId).isEqualTo(root.mFeatureId);
+    }
+
     private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
         private TestDisplayArea(WindowManagerService wms, Rect bounds) {
             super(wms, ANY, "half display area");
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 5bc4c82..baa8645 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1533,7 +1533,7 @@
         unblockDisplayRotation(mDisplayContent);
         final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
         app.setVisible(false);
-        app.setState(Task.ActivityState.RESUMED, "test");
+        app.setState(ActivityRecord.State.RESUMED, "test");
         mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
         mDisplayContent.mOpeningApps.add(app);
         final int newOrientation = getRotatedOrientation(mDisplayContent);
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 03304bb..3741d49 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -24,7 +24,7 @@
 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.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 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;
@@ -50,13 +50,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.spy;
 import static org.testng.Assert.expectThrows;
 
 import android.graphics.Insets;
-import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
@@ -69,7 +69,6 @@
 import android.view.RoundedCorners;
 import android.view.WindowInsets.Side;
 import android.view.WindowInsets.Type;
-import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
 
@@ -109,12 +108,7 @@
         mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
         // We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
         // changing those frames.
-        doNothing().when(mWindow).computeFrame();
-
-        final WindowManager.LayoutParams attrs = mWindow.mAttrs;
-        attrs.width = MATCH_PARENT;
-        attrs.height = MATCH_PARENT;
-        attrs.format = PixelFormat.TRANSLUCENT;
+        doNothing().when(mWindow).computeFrame(any());
 
         spyOn(mStatusBarWindow);
         spyOn(mNavBarWindow);
@@ -219,7 +213,7 @@
     }
 
     @Test
-    public void addingWindow_ignoresInsetsTypes_InWindowTypeWithPredefinedInsets() {
+    public void addingWindow_InWindowTypeWithPredefinedInsets() {
         mDisplayPolicy.removeWindowLw(mStatusBarWindow);  // Removes the existing one.
         WindowState win = createWindow(null, TYPE_STATUS_BAR, "StatusBar");
         win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
@@ -230,7 +224,13 @@
 
         InsetsSourceProvider provider =
                 mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR);
-        assertNotEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame());
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            // In the new flexible insets setup, the insets frame should always respect the window
+            // layout result.
+            assertEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame());
+        } else {
+            assertNotEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame());
+        }
     }
 
     @Test
@@ -733,10 +733,12 @@
 
     @Test
     public void testFixedRotationInsetsSourceFrame() {
+        mDisplayContent.mBaseDisplayHeight = DISPLAY_HEIGHT;
+        mDisplayContent.mBaseDisplayWidth = DISPLAY_WIDTH;
         doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent)
                 .rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord));
-        mWindow.mAboveInsetsState.addSource(mDisplayContent.getInsetsStateController()
-                .getRawInsetsState().peekSource(ITYPE_STATUS_BAR));
+        mWindow.mAboveInsetsState.set(
+                mDisplayContent.getInsetsStateController().getRawInsetsState());
         final Rect frame = mDisplayPolicy.getInsetsPolicy().getInsetsForWindow(mWindow)
                 .getSource(ITYPE_STATUS_BAR).getFrame();
         mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord);
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 b793be7..3f13394 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -313,7 +313,9 @@
         displayInfo.logicalHeight = 2000;
         displayInfo.rotation = ROTATION_0;
 
-        displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
+        WindowManager.LayoutParams attrs = mNavBarWindow.mAttrs;
+        displayPolicy.addWindowLw(mNavBarWindow, attrs);
+        mNavBarWindow.setRequestedSize(attrs.width, attrs.height);
         mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         mImeWindow.mAboveInsetsState.set(state);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 683ed88..3982a83 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -58,8 +58,6 @@
     static final int DISPLAY_HEIGHT = 1000;
     static final int DISPLAY_DENSITY = 320;
 
-    static final int STATUS_BAR_HEIGHT = 10;
-    static final int NAV_BAR_HEIGHT = 15;
     static final int DISPLAY_CUTOUT_HEIGHT = 8;
     static final int IME_HEIGHT = 415;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index bf3ed69..5b04c91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -80,7 +81,7 @@
     }
 
     @Test
-    public void testControlsForDispatch_dockedStackVisible() {
+    public void testControlsForDispatch_dockedTaskVisible() {
         addWindow(TYPE_STATUS_BAR, "statusBar");
         addWindow(TYPE_NAVIGATION_BAR, "navBar");
 
@@ -93,7 +94,20 @@
     }
 
     @Test
-    public void testControlsForDispatch_freeformStackVisible() {
+    public void testControlsForDispatch_multiWindowTaskVisible() {
+        addWindow(TYPE_STATUS_BAR, "statusBar");
+        addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+        final WindowState win = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
+        final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
+
+        // The app must not control any system bars.
+        assertNull(controls);
+    }
+
+    @Test
+    public void testControlsForDispatch_freeformTaskVisible() {
         addWindow(TYPE_STATUS_BAR, "statusBar");
         addWindow(TYPE_NAVIGATION_BAR, "navBar");
 
@@ -101,18 +115,6 @@
                 ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
         final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
 
-        // The app must not control any bars.
-        assertNull(controls);
-    }
-
-    @Test
-    public void testControlsForDispatch_dockedDividerControllerResizing() {
-        addWindow(TYPE_STATUS_BAR, "statusBar");
-        addWindow(TYPE_NAVIGATION_BAR, "navBar");
-        mDisplayContent.getDockedDividerController().setResizing(true);
-
-        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
-
         // The app must not control any system bars.
         assertNull(controls);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index d017c19..1b19a28 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -31,8 +31,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static com.google.common.truth.Truth.assertThat;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 0c6545c..7ebf775 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -36,22 +36,23 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityRecord.State.DESTROYED;
+import static com.android.server.wm.ActivityRecord.State.DESTROYING;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
+import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.Task.ActivityState.DESTROYED;
-import static com.android.server.wm.Task.ActivityState.DESTROYING;
-import static com.android.server.wm.Task.ActivityState.FINISHING;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
 import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
 import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
-import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
@@ -280,11 +281,11 @@
     public void testResumedActivity() {
         final ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build();
         final Task task = r.getTask();
-        assertNull(task.getResumedActivity());
+        assertNull(task.getTopResumedActivity());
         r.setState(RESUMED, "testResumedActivity");
-        assertEquals(r, task.getResumedActivity());
+        assertEquals(r, task.getTopResumedActivity());
         r.setState(PAUSING, "testResumedActivity");
-        assertNull(task.getResumedActivity());
+        assertNull(task.getTopResumedActivity());
     }
 
     @Test
@@ -295,15 +296,15 @@
         final Task task = r.getTask();
         // Ensure moving task between two root tasks updates resumed activity
         r.setState(RESUMED, "testResumedActivityFromTaskReparenting");
-        assertEquals(r, rootTask.getResumedActivity());
+        assertEquals(r, rootTask.getTopResumedActivity());
 
         final Task destRootTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
         task.reparent(destRootTask, true /* toTop */, REPARENT_KEEP_ROOT_TASK_AT_FRONT,
                 false /* animate */, true /* deferResume*/,
                 "testResumedActivityFromTaskReparenting");
 
-        assertNull(rootTask.getResumedActivity());
-        assertEquals(r, destRootTask.getResumedActivity());
+        assertNull(rootTask.getTopResumedActivity());
+        assertEquals(r, destRootTask.getTopResumedActivity());
     }
 
     @Test
@@ -314,15 +315,15 @@
         final Task task = r.getTask();
         // Ensure moving task between two root tasks updates resumed activity
         r.setState(RESUMED, "testResumedActivityFromActivityReparenting");
-        assertEquals(r, rootTask.getResumedActivity());
+        assertEquals(r, rootTask.getTopResumedActivity());
 
         final Task destRootTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
         task.reparent(destRootTask, true /*toTop*/, REPARENT_MOVE_ROOT_TASK_TO_FRONT,
                 false /* animate */, false /* deferResume*/,
                 "testResumedActivityFromActivityReparenting");
 
-        assertNull(rootTask.getResumedActivity());
-        assertEquals(r, destRootTask.getResumedActivity());
+        assertNull(rootTask.getTopResumedActivity());
+        assertEquals(r, destRootTask.getTopResumedActivity());
     }
 
     @Test
@@ -618,9 +619,9 @@
         doReturn(false).when(splitScreenSecondary2).isTranslucent(any());
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
-        assertEquals(TASK_VISIBILITY_INVISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                 splitScreenSecondary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
         // First split-screen secondary should be visible behind another translucent split-screen
@@ -628,9 +629,9 @@
         doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 splitScreenSecondary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
         final Task assistantRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
@@ -642,13 +643,13 @@
         assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 assistantRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_INVISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                 splitScreenPrimary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_INVISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                 splitScreenSecondary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_INVISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
         // Split-screen root tasks should be visible behind a translucent fullscreen root task.
@@ -657,13 +658,13 @@
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 assistantRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 splitScreenPrimary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 splitScreenSecondary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 splitScreenSecondary2.getVisibility(null /* starting */));
 
         // Assistant root task shouldn't be visible behind translucent split-screen root task,
@@ -678,25 +679,25 @@
             assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
             assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
             assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
-            assertEquals(TASK_VISIBILITY_VISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                     assistantRootTask.getVisibility(null /* starting */));
-            assertEquals(TASK_VISIBILITY_INVISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                     splitScreenPrimary.getVisibility(null /* starting */));
-            assertEquals(TASK_VISIBILITY_INVISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                     splitScreenSecondary.getVisibility(null /* starting */));
-            assertEquals(TASK_VISIBILITY_INVISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                     splitScreenSecondary2.getVisibility(null /* starting */));
         } else {
             assertFalse(assistantRootTask.shouldBeVisible(null /* starting */));
             assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
             assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
-            assertEquals(TASK_VISIBILITY_INVISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                     assistantRootTask.getVisibility(null /* starting */));
-            assertEquals(TASK_VISIBILITY_VISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                     splitScreenPrimary.getVisibility(null /* starting */));
-            assertEquals(TASK_VISIBILITY_INVISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                     splitScreenSecondary.getVisibility(null /* starting */));
-            assertEquals(TASK_VISIBILITY_VISIBLE,
+            assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                     splitScreenSecondary2.getVisibility(null /* starting */));
         }
     }
@@ -707,45 +708,51 @@
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, true /* onTop */);
         final Task splitPrimary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */);
+        // Creating as two-level tasks so home task can be reparented to split-secondary root task.
         final Task splitSecondary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
-                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */);
+                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */,
+                true /* twoLevelTask */);
 
         doReturn(false).when(homeRootTask).isTranslucent(any());
         doReturn(false).when(splitPrimary).isTranslucent(any());
         doReturn(false).when(splitSecondary).isTranslucent(any());
 
-
         // Re-parent home to split secondary.
         homeRootTask.reparent(splitSecondary, POSITION_TOP);
         // Current tasks should be visible.
-        assertEquals(TASK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+                splitPrimary.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+                splitSecondary.getVisibility(null /* starting */));
         // Home task should still be visible even though it is a child of another visible task.
-        assertEquals(TASK_VISIBILITY_VISIBLE, homeRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+                homeRootTask.getVisibility(null /* starting */));
 
 
         // Add fullscreen translucent task that partially occludes split tasks
         final Task translucentRootTask = createStandardRootTaskForVisibilityTest(
                 WINDOWING_MODE_FULLSCREEN, true /* translucent */);
         // Fullscreen translucent task should be visible
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 translucentRootTask.getVisibility(null /* starting */));
         // Split tasks should be visible behind translucent
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 splitPrimary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 splitSecondary.getVisibility(null /* starting */));
         // Home task should be visible behind translucent since its parent is visible behind
         // translucent.
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 homeRootTask.getVisibility(null /* starting */));
 
 
         // Hide split-secondary
         splitSecondary.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */);
         // Home split secondary and home task should be invisible.
-        assertEquals(TASK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_INVISIBLE, homeRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+                splitSecondary.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+                homeRootTask.getVisibility(null /* starting */));
     }
 
     @Test
@@ -757,9 +764,9 @@
                 createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
 
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 bottomRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 translucentRootTask.getVisibility(null /* starting */));
     }
 
@@ -775,10 +782,12 @@
                 createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
 
-        assertEquals(TASK_VISIBILITY_INVISIBLE, bottomRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_INVISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+                bottomRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                 translucentRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE, opaqueRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+                opaqueRootTask.getVisibility(null /* starting */));
     }
 
     @Test
@@ -793,10 +802,11 @@
                 createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
 
-        assertEquals(TASK_VISIBILITY_INVISIBLE, bottomRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
+                bottomRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 opaqueRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 translucentRootTask.getVisibility(null /* starting */));
     }
 
@@ -809,9 +819,9 @@
                 createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         true /* translucent */);
 
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 bottomTranslucentRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 translucentRootTask.getVisibility(null /* starting */));
     }
 
@@ -824,9 +834,10 @@
                 createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
                         false /* translucent */);
 
-        assertEquals(TASK_VISIBILITY_INVISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE,
                 bottomTranslucentRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE, opaqueRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+                opaqueRootTask.getVisibility(null /* starting */));
     }
 
     @Test
@@ -840,16 +851,17 @@
         final Task pinnedRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
-        assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                 bottomRootTask.getVisibility(null /* starting */));
-        assertEquals(TASK_VISIBILITY_VISIBLE,
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
                 translucentRootTask.getVisibility(null /* starting */));
         // Add an activity to the pinned root task so it isn't considered empty for visibility
         // check.
         final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
                 .setTask(pinnedRootTask)
                 .build();
-        assertEquals(TASK_VISIBILITY_VISIBLE, pinnedRootTask.getVisibility(null /* starting */));
+        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE,
+                pinnedRootTask.getVisibility(null /* starting */));
     }
 
     @Test
@@ -1142,12 +1154,12 @@
         } else if (twoLevelTask) {
             task = new TaskBuilder(mSupervisor)
                     .setTaskDisplayArea(taskDisplayArea)
-                    .setWindowingMode(windowingMode)
                     .setActivityType(activityType)
                     .setOnTop(onTop)
                     .setCreateActivity(true)
                     .setCreateParentTask(true)
                     .build().getRootTask();
+            task.setWindowingMode(windowingMode);
         } else {
             task = new TaskBuilder(mSupervisor)
                     .setTaskDisplayArea(taskDisplayArea)
@@ -1301,9 +1313,9 @@
         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
         topActivity.info.flags |= FLAG_RESUME_WHILE_PAUSING;
 
-        task.startPausingLocked(false /* uiSleeping */, topActivity,
+        task.startPausing(false /* uiSleeping */, topActivity,
                 "test");
-        verify(task).completePauseLocked(anyBoolean(), eq(topActivity));
+        verify(task).completePause(anyBoolean(), eq(topActivity));
     }
 
     @Test
@@ -1544,7 +1556,7 @@
             activities[i] = r;
             doReturn(null).when(mAtm).getProcessController(
                     eq(r.processName), eq(r.info.applicationInfo.uid));
-            r.setState(Task.ActivityState.INITIALIZING, "test");
+            r.setState(INITIALIZING, "test");
             // Ensure precondition that the activity is opaque.
             assertTrue(r.occludesParent());
             mSupervisor.startSpecificActivity(r, false /* andResume */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 9cf29d4..b8d517a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -31,13 +31,14 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.ActivityRecord.State.FINISHING;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
-import static com.android.server.wm.Task.ActivityState.FINISHING;
-import static com.android.server.wm.Task.ActivityState.PAUSED;
-import static com.android.server.wm.Task.ActivityState.PAUSING;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
-import static com.android.server.wm.Task.ActivityState.STOPPING;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -365,7 +366,7 @@
         TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea();
         doReturn(isFocusedTask ? task : null).when(defaultTaskDisplayArea).getFocusedRootTask();
         mRootWindowContainer.applySleepTokens(true);
-        verify(task, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
+        verify(task, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleeping();
         verify(task, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
                 null /* target */, null /* targetOptions */);
     }
@@ -386,7 +387,7 @@
         // landscape and the portrait lockscreen is shown.
         activity.setLastReportedConfiguration(
                 new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig));
-        activity.setState(Task.ActivityState.STOPPED, "sleep");
+        activity.setState(STOPPED, "sleep");
 
         display.setIsSleeping(true);
         doReturn(false).when(display).shouldSleep();
@@ -626,7 +627,7 @@
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setTask(rootTask).setOnTop(true).build();
-        activity.setState(Task.ActivityState.RESUMED, "test");
+        activity.setState(RESUMED, "test");
 
         // Assume the task is at the topmost position
         assertTrue(rootTask.isTopRootTaskInDisplayArea());
@@ -646,7 +647,7 @@
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setTask(rootTask).setOnTop(true).build();
-        activity.setState(Task.ActivityState.RESUMED, "test");
+        activity.setState(RESUMED, "test");
         taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
 
         // Assume the task is at the topmost position
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 4872ec5..b47e6c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -40,8 +40,10 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -129,7 +131,7 @@
         doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
         mActivity.mVisibleRequested = true;
         mActivity.setSavedState(null /* savedState */);
-        mActivity.setState(Task.ActivityState.RESUMED, "testRestart");
+        mActivity.setState(RESUMED, "testRestart");
         prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
 
         final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
@@ -137,7 +139,7 @@
         // The visible activity should recompute configuration according to the last parent bounds.
         mAtm.mActivityClientController.restartActivityProcessIfVisible(mActivity.appToken);
 
-        assertEquals(Task.ActivityState.RESTARTING_PROCESS, mActivity.getState());
+        assertEquals(RESTARTING_PROCESS, mActivity.getState());
         assertNotEquals(originalOverrideBounds, mActivity.getBounds());
     }
 
@@ -584,7 +586,7 @@
     public void testHandleActivitySizeCompatModeChanged() {
         setUpDisplaySizeWithApp(1000, 2000);
         doReturn(true).when(mTask).isOrganized();
-        mActivity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatModeChanged");
+        mActivity.setState(RESUMED, "testHandleActivitySizeCompatModeChanged");
         prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertFitted();
 
@@ -604,7 +606,7 @@
         mActivity.mVisibleRequested = true;
         mActivity.restartProcessIfVisible();
         // The full lifecycle isn't hooked up so manually set state to resumed
-        mActivity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatModeChanged");
+        mActivity.setState(RESUMED, "testHandleActivitySizeCompatModeChanged");
         mTask.mDisplayContent.handleActivitySizeCompatModeIfNeeded(mActivity);
 
         // Expect null token when switching to non-size-compat mode activity.
@@ -619,7 +621,7 @@
     public void testHandleActivitySizeCompatModeChangedOnDifferentTask() {
         setUpDisplaySizeWithApp(1000, 2000);
         doReturn(true).when(mTask).isOrganized();
-        mActivity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatModeChanged");
+        mActivity.setState(RESUMED, "testHandleActivitySizeCompatModeChanged");
         prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertFitted();
 
@@ -639,7 +641,7 @@
                 .setCreateActivity(true).build();
         final ActivityRecord secondActivity = secondTask.getTopNonFinishingActivity();
         doReturn(true).when(secondTask).isOrganized();
-        secondActivity.setState(Task.ActivityState.RESUMED,
+        secondActivity.setState(RESUMED,
                 "testHandleActivitySizeCompatModeChanged");
         prepareUnresizable(secondActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
 
@@ -1535,6 +1537,30 @@
     }
 
     @Test
+    public void testSandboxDisplayApis_unresizableAppNotSandboxed() {
+        // Set up a display in landscape with an unresizable app.
+        setUpDisplaySizeWithApp(2500, 1000);
+        mActivity.mDisplayContent.setSandboxDisplayApis(false /* sandboxDisplayApis */);
+        prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
+        assertFitted();
+
+        // Activity max bounds not be sandboxed since sandboxing is disabled.
+        assertMaxBoundsInheritDisplayAreaBounds();
+    }
+
+    @Test
+    public void testSandboxDisplayApis_unresizableAppSandboxed() {
+        // Set up a display in landscape with an unresizable app.
+        setUpDisplaySizeWithApp(2500, 1000);
+        mActivity.mDisplayContent.setSandboxDisplayApis(true /* sandboxDisplayApis */);
+        prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
+        assertFitted();
+
+        // Activity max bounds should be sandboxed since sandboxing is enabled.
+        assertActivityMaxBoundsSandboxed();
+    }
+
+    @Test
     public void testResizableApp_notSandboxed() {
         // Set up a display in landscape with a fully resizable app.
         setUpDisplaySizeWithApp(2500, 1000);
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index b89539c..e32b2aa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -178,6 +178,11 @@
     }
 
     @Override
+    public SurfaceControl.Transaction setDisplayFlags(IBinder displayToken, int flags) {
+        return this;
+    }
+
+    @Override
     public SurfaceControl.Transaction setDisplayProjection(IBinder displayToken,
             int orientation, Rect layerStackRect, Rect displayRect) {
         return this;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 67b273a..c45c18d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -37,8 +37,8 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -84,8 +84,7 @@
                 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
         adjacentRootTask.mCreatedByOrganizer = true;
         final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
-        adjacentRootTask.mAdjacentTask = rootTask;
-        rootTask.mAdjacentTask = adjacentRootTask;
+        adjacentRootTask.setAdjacentTaskFragment(rootTask);
 
         taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
         Task actualRootTask = taskDisplayArea.getLaunchRootTask(
@@ -111,8 +110,7 @@
         final Task adjacentRootTask = createTask(
                 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
         adjacentRootTask.mCreatedByOrganizer = true;
-        adjacentRootTask.mAdjacentTask = rootTask;
-        rootTask.mAdjacentTask = adjacentRootTask;
+        adjacentRootTask.setAdjacentTaskFragment(rootTask);
 
         taskDisplayArea.setLaunchRootTask(rootTask,
                 new int[]{WINDOWING_MODE_MULTI_WINDOW}, new int[]{ACTIVITY_TYPE_STANDARD});
@@ -133,8 +131,7 @@
                 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
         adjacentRootTask.mCreatedByOrganizer = true;
         final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
-        adjacentRootTask.mAdjacentTask = rootTask;
-        rootTask.mAdjacentTask = adjacentRootTask;
+        adjacentRootTask.setAdjacentTaskFragment(rootTask);
 
         taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
         final Task actualRootTask = taskDisplayArea.getLaunchRootTask(
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 0ebff1d..629e452 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1257,7 +1257,8 @@
         LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
         spyOn(persister);
 
-        final Task task = getTestTask();
+        final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true)
+                .setCreateParentTask(true).build().getRootTask();
         task.setHasBeenVisible(false);
         task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
         task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index a1f89ec..efe6538 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -57,12 +57,14 @@
 public class WindowFrameTests extends WindowTestsBase {
 
     private DisplayContent mTestDisplayContent;
+    private DisplayFrames mTestDisplayFrames;
 
     @Before
     public void setUp() throws Exception {
         DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo);
         testDisplayInfo.displayCutout = null;
         mTestDisplayContent = createNewDisplay(testDisplayInfo);
+        mTestDisplayFrames = mTestDisplayContent.mDisplayFrames;
     }
 
     // Do not use this function directly in the tests below. Instead, use more explicit function
@@ -99,7 +101,7 @@
         // Here the window has FILL_PARENT, FILL_PARENT
         // so we expect it to fill the entire available frame.
         w.getWindowFrames().setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 0, 0, 1000, 1000);
         assertRelFrame(w, 0, 0, 1000, 1000);
 
@@ -108,14 +110,14 @@
         // and we use mRequestedWidth/mRequestedHeight
         w.mAttrs.width = 300;
         w.mAttrs.height = 300;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         // Explicit width and height without requested width/height
         // gets us nothing.
         assertFrame(w, 0, 0, 0, 0);
 
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         // With requestedWidth/Height we can freely choose our size within the
         // parent bounds.
         assertFrame(w, 0, 0, 300, 300);
@@ -128,14 +130,14 @@
         w.mRequestedWidth = -1;
         w.mAttrs.width = 100;
         w.mAttrs.height = 100;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 0, 0, 100, 100);
         w.mAttrs.flags = 0;
 
         // But sizes too large will be clipped to the containing frame
         w.mRequestedWidth = 1200;
         w.mRequestedHeight = 1200;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 0, 0, 1000, 1000);
 
         // Before they are clipped though windows will be shifted
@@ -143,7 +145,7 @@
         w.mAttrs.y = 300;
         w.mRequestedWidth = 1000;
         w.mRequestedHeight = 1000;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 0, 0, 1000, 1000);
 
         // If there is room to move around in the parent frame the window will be shifted according
@@ -153,18 +155,18 @@
         w.mRequestedWidth = 300;
         w.mRequestedHeight = 300;
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 700, 0, 1000, 300);
         assertRelFrame(w, 700, 0, 1000, 300);
         w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 700, 700, 1000, 1000);
         assertRelFrame(w, 700, 700, 1000, 1000);
         // Window specified  x and y are interpreted as offsets in the opposite
         // direction of gravity
         w.mAttrs.x = 100;
         w.mAttrs.y = 100;
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, 600, 600, 900, 900);
         assertRelFrame(w, 600, 600, 900, 900);
     }
@@ -191,7 +193,7 @@
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertEquals(resolvedTaskBounds, w.getFrame());
@@ -204,7 +206,7 @@
         final int cfBottom = logicalHeight / 2;
         final Rect cf = new Rect(0, 0, cfRight, cfBottom);
         windowFrames.setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertEquals(resolvedTaskBounds, w.getFrame());
         assertEquals(0, w.getRelativeFrame().left);
         assertEquals(0, w.getRelativeFrame().top);
@@ -233,7 +235,7 @@
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
         final WindowFrames windowFrames = w.getWindowFrames();
         windowFrames.setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -249,7 +251,7 @@
         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         task.setBounds(null);
         windowFrames.setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, cf);
     }
 
@@ -285,7 +287,7 @@
         final Rect winRect = new Rect(200, 200, 300, 500);
         task.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, winRect.left, imeFrame.top - winRect.height(), winRect.right, imeFrame.top);
 
         // Now check that it won't get moved beyond the top
@@ -293,7 +295,7 @@
         task.setBounds(winRect);
         w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
 
         // Now we have status bar. Check that it won't go into the status bar area.
@@ -301,14 +303,14 @@
         statusBarFrame.bottom = 60;
         state.getSource(ITYPE_STATUS_BAR).setFrame(statusBarFrame);
         w.getWindowFrames().setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertFrame(w, winRect.left, statusBarFrame.bottom, winRect.right,
                 statusBarFrame.bottom + winRect.height());
 
         // Check that it's moved back without ime insets
         state.removeSource(ITYPE_IME);
         w.getWindowFrames().setFrames(pf, pf);
-        w.computeFrame();
+        w.computeFrame(mTestDisplayFrames);
         assertEquals(winRect, w.getFrame());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index a1b3159..ff13fa5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -42,8 +42,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 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.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
-import static com.android.server.wm.Task.ActivityState.RESUMED;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.WindowContainer.SYNC_STATE_READY;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index f848ce5..1240f9b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -23,6 +23,12 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityRecord.State.PAUSED;
+import static com.android.server.wm.ActivityRecord.State.PAUSING;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.ActivityRecord.State.STARTED;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -309,17 +315,17 @@
 
         callbackResult[0] = 0;
         activity.mVisibleRequested = false;
-        activity.setState(Task.ActivityState.PAUSED, "test");
+        activity.setState(PAUSED, "test");
         mWpc.computeOomAdjFromActivities(callback);
         assertEquals(paused, callbackResult[0]);
 
         callbackResult[0] = 0;
-        activity.setState(Task.ActivityState.STOPPING, "test");
+        activity.setState(STOPPING, "test");
         mWpc.computeOomAdjFromActivities(callback);
         assertEquals(stopping, callbackResult[0]);
 
         callbackResult[0] = 0;
-        activity.setState(Task.ActivityState.STOPPED, "test");
+        activity.setState(STOPPED, "test");
         mWpc.computeOomAdjFromActivities(callback);
         assertEquals(other, callbackResult[0]);
     }
@@ -330,25 +336,25 @@
         spyOn(tracker);
         final ActivityRecord activity = createActivityRecord(mWpc);
         activity.mVisibleRequested = true;
-        activity.setState(Task.ActivityState.STARTED, "test");
+        activity.setState(STARTED, "test");
 
         verify(tracker).onAnyActivityVisible(mWpc);
         assertTrue(mWpc.hasVisibleActivities());
 
-        activity.setState(Task.ActivityState.RESUMED, "test");
+        activity.setState(RESUMED, "test");
 
         verify(tracker).onActivityResumedWhileVisible(mWpc);
         assertTrue(tracker.hasResumedActivity(mWpc.mUid));
 
         activity.makeFinishingLocked();
-        activity.setState(Task.ActivityState.PAUSING, "test");
+        activity.setState(PAUSING, "test");
 
         assertFalse(tracker.hasResumedActivity(mWpc.mUid));
         assertTrue(mWpc.hasForegroundActivities());
 
         activity.setVisibility(false);
         activity.mVisibleRequested = false;
-        activity.setState(Task.ActivityState.STOPPED, "test");
+        activity.setState(STOPPED, "test");
 
         verify(tracker).onAllActivitiesInvisible(mWpc);
         assertFalse(mWpc.hasVisibleActivities());
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 92b670e..e83db78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -946,4 +946,19 @@
         assertNotNull(state.peekSource(ITYPE_IME));
         assertTrue(state.getSource(ITYPE_IME).isVisible());
     }
+
+    @Test
+    public void testRequestedVisibility() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        app.mActivityRecord.setVisible(false);
+        app.mActivityRecord.setVisibility(false /* visible */, false /* deferHidingClient */);
+        assertFalse(app.isVisibleRequested());
+
+        // It doesn't have a surface yet, but should still be visible requested.
+        app.setHasSurface(false);
+        app.mActivityRecord.setVisibility(true /* visible */, false /* deferHidingClient */);
+
+        assertFalse(app.isVisible());
+        assertTrue(app.isVisibleRequested());
+    }
 }
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 5880899..050fd80 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -29,11 +30,13 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.os.Process.SYSTEM_UID;
 import static android.view.View.VISIBLE;
+import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -83,10 +86,12 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Gravity;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IWindow;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
+import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
@@ -132,6 +137,9 @@
     DisplayInfo mDisplayInfo = new DisplayInfo();
     DisplayContent mDefaultDisplay;
 
+    static final int STATUS_BAR_HEIGHT = 10;
+    static final int NAV_BAR_HEIGHT = 15;
+
     /**
      * It is {@link #mDefaultDisplay} by default. If the test class or method is annotated with
      * {@link UseTestDisplay}, it will be an additional display.
@@ -268,6 +276,14 @@
         }
         if (addAll || ArrayUtils.contains(requestedWindows, W_STATUS_BAR)) {
             mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
+            if (INSETS_LAYOUT_GENERALIZATION) {
+                mStatusBarWindow.mAttrs.height = STATUS_BAR_HEIGHT;
+                mStatusBarWindow.mAttrs.gravity = Gravity.TOP;
+                mStatusBarWindow.mAttrs.layoutInDisplayCutoutMode =
+                        LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+                mStatusBarWindow.setRequestedSize(WindowManager.LayoutParams.MATCH_PARENT,
+                        STATUS_BAR_HEIGHT);
+            }
         }
         if (addAll || ArrayUtils.contains(requestedWindows, W_NOTIFICATION_SHADE)) {
             mNotificationShadeWindow = createCommonWindow(null, TYPE_NOTIFICATION_SHADE,
@@ -275,6 +291,15 @@
         }
         if (addAll || ArrayUtils.contains(requestedWindows, W_NAVIGATION_BAR)) {
             mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
+            if (INSETS_LAYOUT_GENERALIZATION) {
+                mNavBarWindow.mAttrs.height = NAV_BAR_HEIGHT;
+                mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM;
+                mNavBarWindow.mAttrs.paramsForRotation = new WindowManager.LayoutParams[4];
+                for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+                    mNavBarWindow.mAttrs.paramsForRotation[rot] =
+                            getNavBarLayoutParamsForRotation(rot);
+                }
+            }
         }
         if (addAll || ArrayUtils.contains(requestedWindows, W_DOCK_DIVIDER)) {
             mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
@@ -302,6 +327,37 @@
         waitUntilHandlersIdle();
     }
 
+    private WindowManager.LayoutParams getNavBarLayoutParamsForRotation(int rotation) {
+        int width = WindowManager.LayoutParams.MATCH_PARENT;
+        int height = WindowManager.LayoutParams.MATCH_PARENT;
+        int gravity = Gravity.BOTTOM;
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            switch (rotation) {
+                case ROTATION_UNDEFINED:
+                case Surface.ROTATION_0:
+                case Surface.ROTATION_180:
+                    height = NAV_BAR_HEIGHT;
+                    break;
+                case Surface.ROTATION_90:
+                    gravity = Gravity.RIGHT;
+                    width = NAV_BAR_HEIGHT;
+                    break;
+                case Surface.ROTATION_270:
+                    gravity = Gravity.LEFT;
+                    width = NAV_BAR_HEIGHT;
+                    break;
+            }
+        }
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR);
+        lp.width = width;
+        lp.height = height;
+        if (INSETS_LAYOUT_GENERALIZATION) {
+            lp.gravity = gravity;
+        }
+        return lp;
+    }
+
     void beforeCreateTestDisplay() {
         // Called before display is created.
     }
diff --git a/services/usage/OWNERS b/services/usage/OWNERS
index 9daa093..6c20e74 100644
--- a/services/usage/OWNERS
+++ b/services/usage/OWNERS
@@ -2,3 +2,5 @@
 varunshah@google.com
 huiyu@google.com
 yamasani@google.com
+
+per-file *StorageStats* = file:/core/java/android/os/storage/OWNERS
\ No newline at end of file
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index b056de0..763159a 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -208,7 +208,7 @@
     public boolean isReservedSupported(String volumeUuid, String callingPackage) {
         if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
             return SystemProperties.getBoolean(StorageManager.PROP_HAS_RESERVED, false)
-                    || Build.IS_CONTAINER;
+                    || Build.IS_ARC;
         } else {
             return false;
         }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 7f24c36..b966643 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -239,8 +239,7 @@
                 mHandler.updateState(state);
             } else if ("GETPROTOCOL".equals(accessory)) {
                 if (DEBUG) Slog.d(TAG, "got accessory get protocol");
-                long elapsedRealtime = SystemClock.elapsedRealtime();
-                mHandler.setAccessoryUEventTime(elapsedRealtime);
+                mHandler.setAccessoryUEventTime(SystemClock.elapsedRealtime());
                 resetAccessoryHandshakeTimeoutHandler();
             } else if ("SENDSTRING".equals(accessory)) {
                 if (DEBUG) Slog.d(TAG, "got accessory send string");
@@ -465,6 +464,8 @@
         }
     }
 
+    //TODO It is not clear that this method serves any purpose (at least on Pixel devices)
+    // consider removing
     private static void initRndisAddress() {
         // configure RNDIS ethernet address based on our serial number using the same algorithm
         // we had been previously using in kernel board files
@@ -484,7 +485,7 @@
         try {
             FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
         } catch (IOException e) {
-            Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
+            Slog.i(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
         }
     }
 
@@ -760,9 +761,6 @@
         }
 
         private void broadcastUsbAccessoryHandshake() {
-            long elapsedRealtime = SystemClock.elapsedRealtime();
-            long accessoryHandShakeEnd = elapsedRealtime;
-
             // send a sticky broadcast containing USB accessory handshake information
             Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_HANDSHAKE)
                     .putExtra(UsbManager.EXTRA_ACCESSORY_UEVENT_TIME,
@@ -772,7 +770,7 @@
                     .putExtra(UsbManager.EXTRA_ACCESSORY_START,
                             mStartAccessory)
                     .putExtra(UsbManager.EXTRA_ACCESSORY_HANDSHAKE_END,
-                            accessoryHandShakeEnd);
+                            SystemClock.elapsedRealtime());
 
             if (DEBUG) {
                 Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
@@ -780,7 +778,6 @@
 
             sendStickyBroadcast(intent);
             resetUsbAccessoryHandshakeDebuggingInfo();
-            accessoryHandShakeEnd = 0L;
         }
 
         protected void updateUsbStateBroadcastIfNeeded(long functions) {
@@ -1935,14 +1932,14 @@
                     }
                     break;
                 case MSG_GET_CURRENT_USB_FUNCTIONS:
-                    Slog.e(TAG, "prcessing MSG_GET_CURRENT_USB_FUNCTIONS");
+                    Slog.i(TAG, "processing MSG_GET_CURRENT_USB_FUNCTIONS");
                     mCurrentUsbFunctionsReceived = true;
 
                     if (mCurrentUsbFunctionsRequested) {
-                        Slog.e(TAG, "updating mCurrentFunctions");
+                        Slog.i(TAG, "updating mCurrentFunctions");
                         // Mask out adb, since it is stored in mAdbEnabled
                         mCurrentFunctions = ((Long) msg.obj) & ~UsbManager.FUNCTION_ADB;
-                        Slog.e(TAG,
+                        Slog.i(TAG,
                                 "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
                         mCurrentFunctionsApplied = msg.arg1 == 1;
                     }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index a3b5fc7..be37a91 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -36,7 +36,6 @@
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
 import android.hardware.soundtrigger.SoundTrigger.SoundModel;
-import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
 import android.hardware.soundtrigger.SoundTriggerModule;
 import android.os.Binder;
 import android.os.DeadObjectException;
@@ -109,9 +108,6 @@
     private boolean mCallActive = false;
     private @SoundTriggerPowerSaveMode int mSoundTriggerPowerSaveMode =
             PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
-    // Indicates if the native sound trigger service is disabled or not.
-    // This is an indirect indication of the microphone being open in some other application.
-    private boolean mServiceDisabled = false;
 
     // Whether ANY recognition (keyphrase or generic) has been requested.
     private boolean mRecognitionRequested = false;
@@ -862,23 +858,19 @@
     }
 
     @Override
-    public void onSoundModelUpdate(SoundModelEvent event) {
-        if (event == null) {
-            Slog.w(TAG, "Invalid sound model event!");
-            return;
-        }
-        if (DBG) Slog.d(TAG, "onSoundModelUpdate: " + event);
+    public void onModelUnloaded(int modelHandle) {
+        if (DBG) Slog.d(TAG, "onModelUnloaded: " + modelHandle);
         synchronized (mLock) {
             MetricsLogger.count(mContext, "sth_sound_model_updated", 1);
-            onSoundModelUpdatedLocked(event);
+            onModelUnloadedLocked(modelHandle);
         }
     }
 
     @Override
-    public void onServiceStateChange(int state) {
-        if (DBG) Slog.d(TAG, "onServiceStateChange, state: " + state);
+    public void onResourcesAvailable() {
+        if (DBG) Slog.d(TAG, "onResourcesAvailable");
         synchronized (mLock) {
-            onServiceStateChangedLocked(SoundTrigger.SERVICE_STATE_DISABLED == state);
+            onResourcesAvailableLocked();
         }
     }
 
@@ -910,15 +902,14 @@
         updateAllRecognitionsLocked();
     }
 
-    private void onSoundModelUpdatedLocked(SoundModelEvent event) {
-        // TODO: Handle sound model update here.
+    private void onModelUnloadedLocked(int modelHandle) {
+        ModelData modelData = getModelDataForLocked(modelHandle);
+        if (modelData != null) {
+            modelData.setNotLoaded();
+        }
     }
 
-    private void onServiceStateChangedLocked(boolean disabled) {
-        if (disabled == mServiceDisabled) {
-            return;
-        }
-        mServiceDisabled = disabled;
+    private void onResourcesAvailableLocked() {
         updateAllRecognitionsLocked();
     }
 
@@ -1039,7 +1030,6 @@
             if (mModule != null) {
                 mModule.detach();
                 mModule = null;
-                mServiceDisabled = false;
             }
         }
     }
@@ -1114,8 +1104,6 @@
             pw.print("  call active=");
             pw.println(mCallActive);
             pw.println("  SoundTrigger Power State=" + mSoundTriggerPowerSaveMode);
-            pw.print("  service disabled=");
-            pw.println(mServiceDisabled);
         }
     }
 
@@ -1329,8 +1317,7 @@
             mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
         }
 
-        return !mCallActive && !mServiceDisabled
-                && isRecognitionAllowedByPowerState(
+        return !mCallActive && isRecognitionAllowedByPowerState(
                 modelData);
     }
 
@@ -1571,6 +1558,10 @@
             mModelState = MODEL_LOADED;
         }
 
+        synchronized void setNotLoaded() {
+            mModelState = MODEL_NOTLOADED;
+        }
+
         synchronized boolean isModelStarted() {
             return mModelState == MODEL_STARTED;
         }
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index 1963ff3..391dce1 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -23,6 +23,46 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "CtsTelephonySdk28TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephony2TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephony3TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsSimRestrictedApisTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephonyProviderTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ],
   "presubmit-large": [
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 30403f4..711a090 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1757,11 +1757,13 @@
         public abstract void onSetDeviceOrientation(int rotation);
 
         /**
-         * Sets camera zoom ratio.
+         * Sets the camera zoom ratio.
          * <p>
          * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}.
          *
-         * @param value The camera zoom ratio.
+         * @param value The camera zoom ratio; for the current camera, should be a value in the
+         * range defined by
+         * {@link android.hardware.camera2.CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}.
          */
         public abstract void onSetZoom(float value);
 
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index f20ee7e..c365648 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -764,11 +764,13 @@
         public abstract void setDeviceOrientation(int rotation);
 
         /**
-         * Sets camera zoom ratio.
+         * Sets the camera zoom ratio.
          * <p>
          * Handled by {@link Connection.VideoProvider#onSetZoom(float)}.
          *
-         * @param value The camera zoom ratio.
+         * @param value The camera zoom ratio; for the current camera, should be a value in the
+         * range defined by
+         * {@link android.hardware.camera2.CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE}.
          */
         public abstract void setZoom(float value);
 
diff --git a/telephony/TEST_MAPPING b/telephony/TEST_MAPPING
index d585666..02d4eb3 100644
--- a/telephony/TEST_MAPPING
+++ b/telephony/TEST_MAPPING
@@ -23,6 +23,46 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "CtsTelephony2TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },    
+    {
+      "name": "CtsTelephonySdk28TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephony3TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsSimRestrictedApisTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephonyProviderTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ]
 }
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 5171cf9..73d1710 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2666,7 +2666,8 @@
      * @throws IllegalArgumentException if contentUri is empty
      */
     public void sendMultimediaMessage(@NonNull Context context, @NonNull Uri contentUri,
-            @Nullable String locationUrl, @Nullable Bundle configOverrides,
+            @Nullable String locationUrl,
+            @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides,
             @Nullable PendingIntent sentIntent, long messageId) {
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
@@ -2742,7 +2743,8 @@
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
      */
     public void downloadMultimediaMessage(@NonNull Context context, @NonNull String locationUrl,
-            @NonNull Uri contentUri, @Nullable Bundle configOverrides,
+            @NonNull Uri contentUri,
+            @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides,
             @Nullable PendingIntent downloadedIntent, long messageId) {
         if (TextUtils.isEmpty(locationUrl)) {
             throw new IllegalArgumentException("Empty MMS location URL");
diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java
index 88c66ac..f4e2ade 100644
--- a/telephony/java/android/telephony/TelephonyDisplayInfo.java
+++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java
@@ -79,7 +79,7 @@
      *   <li>The device is connected to the NR cellular network on millimeter wave bands. </li>
      *   <li>The device is connected to the specific network which the carrier is using
      *   proprietary means to provide a faster overall data connection than would be otherwise
-     *   possible. This may include using other bands unique to the carrier, or carrier
+     *   possible.  This may include using other bands unique to the carrier, or carrier
      *   aggregation, for example.</li>
      * </ul>
      * One of the use case is that UX can show a different icon, for example, "5G+"
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 64aa2994..0f32e5d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8512,13 +8512,13 @@
 
     /**
      * Get the PLMN chosen for Manual Network Selection if active.
-     * Return null string if in automatic selection.
+     * Return empty string if in automatic selection.
      *
      * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
      * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
      * (see {@link #hasCarrierPrivileges})
      *
-     * @return manually selected network info on success or null string on failure
+     * @return manually selected network info on success or empty string on failure
      */
     @SuppressAutoDoc // No support carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -8531,7 +8531,7 @@
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getManualNetworkSelectionPlmn RemoteException", ex);
         }
-        return null;
+        return "";
     }
 
     /**
@@ -11115,14 +11115,10 @@
     @UnsupportedAppUsage
     public int getSubIdForPhoneAccount(@Nullable PhoneAccount phoneAccount) {
         int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-        try {
-            ITelephony service = getITelephony();
-            if (service != null) {
-                retval = service.getSubIdForPhoneAccount(phoneAccount);
-            }
-        } catch (RemoteException e) {
+        if (phoneAccount != null
+                && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            retval = getSubscriptionId(phoneAccount.getAccountHandle());
         }
-
         return retval;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a096c1f..da15bea 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1354,11 +1354,6 @@
             String callingFeatureId);
 
     /**
-     * Returns the subscription ID associated with the specified PhoneAccount.
-     */
-    int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
-
-    /**
      * Returns the subscription ID associated with the specified PhoneAccountHandle.
      */
     int getSubIdForPhoneAccountHandle(in PhoneAccountHandle phoneAccountHandle,
diff --git a/tests/BootImageProfileTest/OWNERS b/tests/BootImageProfileTest/OWNERS
index 7ee0d9a..57303e7 100644
--- a/tests/BootImageProfileTest/OWNERS
+++ b/tests/BootImageProfileTest/OWNERS
@@ -1,4 +1,4 @@
 calin@google.com
-mathieuc@google.com
 ngeoffray@google.com
+vmarko@google.com
 yawanng@google.com
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 217a72b..7731e09 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -25,11 +25,17 @@
 
 android_test {
     name: "FlickerTests",
-    srcs: ["src/**/*.java", "src/**/*.kt"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
     manifest: "AndroidManifest.xml",
     test_config: "AndroidTest.xml",
     platform_apis: true,
     certificate: "platform",
+    optimize: {
+        enabled: false,
+    },
     test_suites: ["device-tests"],
     libs: ["android.test.runner"],
     static_libs: [
@@ -46,6 +52,9 @@
 java_library {
     name: "wm-flicker-common-assertions",
     platform_apis: true,
+    optimize: {
+        enabled: false,
+    },
     srcs: [
         "src/**/*Assertions.java",
         "src/**/*Assertions.kt",
@@ -56,20 +65,23 @@
     static_libs: [
         "flickerlib",
         "truth-prebuilt",
-        "app-helpers-core"
+        "app-helpers-core",
     ],
 }
 
 java_library {
     name: "wm-flicker-common-app-helpers",
     platform_apis: true,
+    optimize: {
+        enabled: false,
+    },
     srcs: [
-        "**/helpers/*"
+        "**/helpers/*",
     ],
     static_libs: [
         "flickerlib",
         "flickertestapplib",
         "truth-prebuilt",
-        "app-helpers-core"
+        "app-helpers-core",
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index a540dff..b9cf27f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -25,15 +25,21 @@
 
 val HOME_WINDOW_TITLE = arrayOf("Wallpaper", "Launcher")
 
-fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
-    assertWm {
-        this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
+fun FlickerTestParameter.statusBarWindowIsVisible() {
+    assertWmStart {
+        this.isAboveAppWindow(STATUS_BAR_WINDOW_NAME)
+    }
+    assertWmEnd {
+        this.isAboveAppWindow(STATUS_BAR_WINDOW_NAME)
     }
 }
 
-fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
-    assertWm {
-        this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
+fun FlickerTestParameter.navBarWindowIsVisible() {
+    assertWmStart {
+        this.isAboveAppWindow(NAV_BAR_WINDOW_NAME)
+    }
+    assertWmEnd {
+        this.isAboveAppWindow(NAV_BAR_WINDOW_NAME)
     }
 }
 
@@ -111,37 +117,21 @@
     }
 }
 
-@JvmOverloads
-fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
-    if (rotatesScreen) {
-        assertLayers {
-            this.isVisible(NAV_BAR_LAYER_NAME)
-                .then()
-                .isInvisible(NAV_BAR_LAYER_NAME)
-                .then()
-                .isVisible(NAV_BAR_LAYER_NAME)
-        }
-    } else {
-        assertLayers {
-            this.isVisible(NAV_BAR_LAYER_NAME)
-        }
+fun FlickerTestParameter.navBarLayerIsVisible() {
+    assertLayersStart {
+        this.isVisible(NAV_BAR_LAYER_NAME)
+    }
+    assertLayersEnd {
+        this.isVisible(NAV_BAR_LAYER_NAME)
     }
 }
 
-@JvmOverloads
-fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
-    if (rotatesScreen) {
-        assertLayers {
-            this.isVisible(STATUS_BAR_LAYER_NAME)
-                .then()
-                .isInvisible(STATUS_BAR_LAYER_NAME)
-                .then()
-                .isVisible(STATUS_BAR_LAYER_NAME)
-        }
-    } else {
-        assertLayers {
-            this.isVisible(STATUS_BAR_LAYER_NAME)
-        }
+fun FlickerTestParameter.statusBarLayerIsVisible() {
+    assertLayersStart {
+        this.isVisible(STATUS_BAR_LAYER_NAME)
+    }
+    assertLayersEnd {
+        this.isVisible(STATUS_BAR_LAYER_NAME)
     }
 }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index f7f977d..5c1e446 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -28,14 +28,14 @@
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.flicker.launcherLayerReplacesApp
 import com.android.server.wm.flicker.launcherWindowBecomesVisible
 import org.junit.Test
@@ -66,26 +66,26 @@
 
     @Presubmit
     @Test
-    open fun navBarWindowIsAlwaysVisible() {
-        testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsVisible() {
+        testSpec.navBarWindowIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() {
-        testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsVisible() {
+        testSpec.statusBarWindowIsVisible()
     }
 
     @FlakyTest
     @Test
-    open fun navBarLayerIsAlwaysVisible() {
-        testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+    open fun navBarLayerIsVisible() {
+        testSpec.navBarLayerIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun statusBarLayerIsAlwaysVisible() {
-        testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+    open fun statusBarLayerIsVisible() {
+        testSpec.statusBarLayerIsVisible()
     }
 
     @FlakyTest
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 b5757fd..5d44701 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
@@ -17,7 +17,9 @@
 package com.android.server.wm.flicker.ime
 
 import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.view.Surface
 import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -29,15 +31,14 @@
 import com.android.server.wm.flicker.annotation.Group2
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,6 +47,14 @@
 
 /**
  * Test IME window closing back to app window transitions.
+ *
+ * This test doesn't work on 90 degrees. According to the InputMethodService documentation:
+ *
+ *     Don't show if this is not explicitly requested by the user and the input method
+ *     is fullscreen. That would be too disruptive.
+ *
+ * More details on b/190352379
+ *
  * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
  */
 @RequiresDevice
@@ -79,45 +88,67 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         testSpec.assertWm {
-            this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
-                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
-                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+            this.visibleWindowsShownMoreThanOneConsecutiveEntry()
         }
     }
 
     @Presubmit
     @Test
-    fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+    fun imeAppWindowIsAlwaysVisible() {
+        testSpec.assertWm {
+            this.showsAppWindowOnTop(testApp.getPackage())
+        }
+    }
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @FlakyTest
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
 
+    @Postsubmit
+    @Test
+    fun imeLayerVisibleStart() {
+        testSpec.assertLayersStart {
+            this.isVisible(IME_LAYER_TITLE)
+        }
+    }
+
+    @Postsubmit
+    @Test
+    fun imeLayerInvisibleEnd() {
+        testSpec.assertLayersEnd {
+            this.isInvisible(IME_LAYER_TITLE)
+        }
+    }
+
     @Presubmit
     @Test
     fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
 
     @Presubmit
     @Test
-    fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+    fun imeAppLayerIsAlwaysVisible() {
+        testSpec.assertLayers {
+            this.isVisible(testApp.getPackage())
+        }
+    }
 
     @FlakyTest
     @Test
@@ -145,8 +176,11 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(repetitions = 5,
+                    // b/190352379 (IME doesn't show on app launch in 90 degrees)
+                    supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
                 )
         }
     }
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 549e44c..cf3da79 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
@@ -17,6 +17,7 @@
 package com.android.server.wm.flicker.ime
 
 import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
@@ -30,14 +31,14 @@
 import com.android.server.wm.flicker.annotation.Group2
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -47,6 +48,14 @@
 
 /**
  * Test IME window closing back to app window transitions.
+ *
+ * This test doesn't work on 90 degrees. According to the InputMethodService documentation:
+ *
+ *     Don't show if this is not explicitly requested by the user and the input method
+ *     is fullscreen. That would be too disruptive.
+ *
+ * More details on b/190352379
+ *
  * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
  */
 @RequiresDevice
@@ -82,42 +91,64 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         testSpec.assertWm {
-            this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
-                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
-                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+            this.visibleWindowsShownMoreThanOneConsecutiveEntry()
         }
     }
 
-    @FlakyTest
+    @FlakyTest(bugId = 190189685)
     @Test
-    fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
-
-    @FlakyTest
-    @Test
-    fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+    fun imeAppWindowBecomesInvisible() {
+        testSpec.assertWm {
+            this.showsAppWindowOnTop(testApp.getPackage())
+                .then()
+                .appWindowNotOnTop(testApp.getPackage())
+        }
+    }
 
     @Presubmit
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
         Surface.ROTATION_0)
 
-    @FlakyTest
+    @Postsubmit
+    @Test
+    fun imeLayerVisibleStart() {
+        testSpec.assertLayersStart {
+            this.isVisible(IME_LAYER_TITLE)
+        }
+    }
+
+    @Postsubmit
+    @Test
+    fun imeLayerInvisibleEnd() {
+        testSpec.assertLayersEnd {
+            this.isInvisible(IME_LAYER_TITLE)
+        }
+    }
+
+    @Postsubmit
     @Test
     fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
 
     @Presubmit
     @Test
-    fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+    fun imeAppLayerBecomesInvisible() {
+        testSpec.assertLayers {
+            this.isVisible(testApp.getPackage())
+                .then()
+                .isInvisible(testApp.getPackage())
+        }
+    }
 
     @FlakyTest
     @Test
@@ -133,11 +164,11 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @FlakyTest
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
@@ -154,8 +185,11 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(repetitions = 1,
+                    // b/190352379 (IME doesn't show on app launch in 90 degrees)
+                    supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
                 )
         }
     }
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 82ca074..9367905 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
@@ -28,13 +28,13 @@
 import com.android.server.wm.flicker.annotation.Group2
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import org.junit.Assume
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.FixMethodOrder
@@ -61,7 +61,7 @@
         return FlickerBuilder(instrumentation).apply {
             setup {
                 test {
-                    testApp.launchViaIntent()
+                    testApp.launchViaIntent(wmHelper)
                 }
                 eachRun {
                     testApp.openIME(device, wmHelper)
@@ -80,11 +80,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
@@ -102,11 +102,11 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 703e4a1..aa227a9 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
@@ -30,13 +30,13 @@
 import com.android.server.wm.flicker.annotation.Group2
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -84,11 +84,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
@@ -110,11 +110,11 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 3dfa31d..c42f307 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -20,20 +20,21 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 
 const val IME_WINDOW_TITLE = "InputMethod"
+const val IME_LAYER_TITLE = "$IME_WINDOW_TITLE#0"
 
 fun FlickerTestParameter.imeLayerBecomesVisible() {
     assertLayers {
-        this.isInvisible(IME_WINDOW_TITLE)
+        this.isInvisible(IME_LAYER_TITLE)
             .then()
-            .isVisible(IME_WINDOW_TITLE)
+            .isVisible(IME_LAYER_TITLE)
     }
 }
 
 fun FlickerTestParameter.imeLayerBecomesInvisible() {
     assertLayers {
-        this.isVisible(IME_WINDOW_TITLE)
+        this.isVisible(IME_LAYER_TITLE)
             .then()
-            .isInvisible(IME_WINDOW_TITLE)
+            .isInvisible(IME_LAYER_TITLE)
     }
 }
 
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 cae1b16..2689244 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
@@ -28,16 +28,16 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group2
 import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -81,11 +81,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
@@ -97,11 +97,11 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index d61422f..d6e0abe 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
@@ -30,18 +30,18 @@
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.launcherWindowBecomesInvisible
 import com.android.server.wm.flicker.appLayerReplacesLauncher
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -92,11 +92,11 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @Presubmit
     @Test
@@ -127,11 +127,11 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 0cae37c..0921daa 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
@@ -33,11 +33,11 @@
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -112,19 +112,19 @@
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
 
     @FlakyTest
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
 
     @FlakyTest
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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 9ff0bdf..e217bb3 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
@@ -70,8 +70,8 @@
 
     @FlakyTest
     @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
     }
 
     @FlakyTest
@@ -82,8 +82,8 @@
 
     @FlakyTest
     @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        super.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsVisible() {
+        super.statusBarLayerIsVisible()
     }
 
     @FlakyTest
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 b073a7c..dfc87a2 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
@@ -65,14 +65,14 @@
 
     @FlakyTest
     @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
     }
 
     @FlakyTest
     @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        super.statusBarLayerIsAlwaysVisible()
+    override fun statusBarLayerIsVisible() {
+        super.statusBarLayerIsVisible()
     }
 
     @FlakyTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index b304d5f..7b74cc7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -30,15 +30,15 @@
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import com.android.server.wm.flicker.launcherWindowBecomesInvisible
 import org.junit.Test
 
@@ -71,14 +71,14 @@
 
     @Presubmit
     @Test
-    open fun navBarWindowIsAlwaysVisible() {
-        testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsVisible() {
+        testSpec.navBarWindowIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun navBarLayerIsAlwaysVisible() {
-        testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+    open fun navBarLayerIsVisible() {
+        testSpec.navBarLayerIsVisible()
     }
 
     @Presubmit
@@ -89,14 +89,14 @@
 
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() {
-        testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsVisible() {
+        testSpec.statusBarWindowIsVisible()
     }
 
     @Presubmit
     @Test
-    open fun statusBarLayerIsAlwaysVisible() {
-        testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+    open fun statusBarLayerIsVisible() {
+        testSpec.statusBarLayerIsVisible()
     }
 
     @Presubmit
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 e2705c7..8cd8c78 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
@@ -67,8 +67,8 @@
 
     @FlakyTest
     @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        super.navBarLayerIsAlwaysVisible()
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
     }
 
     @FlakyTest
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 69e8a8d..9d15138 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
@@ -25,7 +25,12 @@
 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.endRotation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -73,22 +78,47 @@
         }
     }
 
-    @Postsubmit
-    @Test
-    override fun statusBarLayerRotatesScales() {
-        super.statusBarLayerRotatesScales()
-    }
-
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() {
-        super.navBarWindowIsAlwaysVisible()
+    fun statusBarWindowIsVisible() {
+        testSpec.statusBarWindowIsVisible()
     }
 
     @FlakyTest
     @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        super.statusBarLayerIsAlwaysVisible()
+    fun statusBarLayerIsVisible() {
+        testSpec.statusBarLayerIsVisible()
+    }
+
+    @Postsubmit
+    @Test
+    fun statusBarLayerRotatesScales() {
+        testSpec.statusBarLayerRotatesScales(
+            testSpec.config.startRotation, testSpec.config.endRotation)
+    }
+
+    @Presubmit
+    @Test
+    override fun navBarWindowIsVisible() {
+        super.navBarWindowIsVisible()
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() {
+        super.navBarLayerRotatesAndScales()
+    }
+
+    @FlakyTest
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+        super.visibleLayersShownMoreThanOneConsecutiveEntry()
     }
 
     companion object {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 4b888cd..0cf07bd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -18,7 +18,6 @@
 
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -28,14 +27,11 @@
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.Test
 
@@ -69,19 +65,19 @@
         }
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
-    open fun navBarWindowIsAlwaysVisible() {
-        testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsVisible() {
+        testSpec.navBarWindowIsVisible()
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
-    open fun navBarLayerIsAlwaysVisible() {
-        testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = true)
+    open fun navBarLayerIsVisible() {
+        testSpec.navBarLayerIsVisible()
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
     open fun navBarLayerRotatesAndScales() {
         testSpec.navBarLayerRotatesAndScales(
@@ -90,25 +86,6 @@
 
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() {
-        testSpec.statusBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest
-    @Test
-    open fun statusBarLayerIsAlwaysVisible() {
-        testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = true)
-    }
-
-    @FlakyTest
-    @Test
-    open fun statusBarLayerRotatesScales() {
-        testSpec.statusBarLayerRotatesScales(
-            testSpec.config.startRotation, testSpec.config.endRotation)
-    }
-
-    @FlakyTest
-    @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index b153bec..caa92ba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -18,6 +18,7 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.view.WindowManager
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -27,6 +28,7 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -60,16 +62,33 @@
             }
         }
 
-    @FlakyTest(bugId = 140855415)
+    @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() {
-        super.statusBarWindowIsAlwaysVisible()
+    fun appWindowFullScreen() {
+        testSpec.assertWm {
+            this.invoke("isFullScreen") {
+                val appWindow = it.windowState(testApp.`package`)
+                val flags = appWindow.windowState?.attributes?.flags ?: 0
+                appWindow.verify("isFullScreen")
+                    .that(flags.and(WindowManager.LayoutParams.FLAG_FULLSCREEN))
+                    .isGreaterThan(0)
+            }
+        }
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Postsubmit
     @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        super.statusBarLayerIsAlwaysVisible()
+    fun appWindowSeamlessRotation() {
+        testSpec.assertWm {
+            this.invoke("isRotationSeamless") {
+                val appWindow = it.windowState(testApp.`package`)
+                val rotationAnimation = appWindow.windowState?.attributes?.rotationAnimation ?: 0
+                appWindow.verify("isRotationSeamless")
+                    .that(rotationAnimation
+                        .and(WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS))
+                    .isGreaterThan(0)
+            }
+        }
     }
 
     @Presubmit
@@ -90,12 +109,46 @@
         }
     }
 
+    @Presubmit
+    @Test
+    fun statusBarWindowIsAlwaysInvisible() {
+        testSpec.assertWm {
+            this.hidesAboveAppWindow(WindowManagerStateHelper.STATUS_BAR_WINDOW_NAME)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun statusBarLayerIsAlwaysInvisible() {
+        testSpec.assertLayers {
+            this.isInvisible(WindowManagerStateHelper.STATUS_BAR_LAYER_NAME)
+        }
+    }
+
     @Postsubmit
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
     }
 
+    @FlakyTest
+    @Test
+    override fun navBarWindowIsVisible() {
+        super.navBarWindowIsVisible()
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerIsVisible() {
+        super.navBarLayerIsVisible()
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() {
+        super.navBarLayerRotatesAndScales()
+    }
+
     companion object {
         private val testFactory = FlickerTestParameterFactory.getInstance()
 
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 2c6c8d7..1381c0a 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -73,6 +73,14 @@
             android:text="@string/play_trigger"
             android:onClick="onPlayTriggerButtonClicked"
             android:padding="20dp" />
+
+        <Button
+            android:id="@+id/get_state_id"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/get_model_state"
+            android:onClick="onGetModelStateButtonClicked"
+            android:padding="20dp" />
     </LinearLayout>
 
     <LinearLayout
diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
index c48b648..adb0fcf 100644
--- a/tests/SoundTriggerTestApp/res/values/strings.xml
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -22,6 +22,7 @@
     <string name="start_recog">Start</string>
     <string name="stop_recog">Stop</string>
     <string name="play_trigger">Play Trigger Audio</string>
+    <string name="get_model_state">Get State</string>
     <string name="capture">Capture Audio</string>
     <string name="stop_capture">Stop Capturing Audio</string>
     <string name="play_capture">Play Captured Audio</string>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
index c3c4cf5..72aa38d 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java
@@ -257,6 +257,14 @@
         }
     }
 
+    public synchronized void onGetModelStateButtonClicked(View v) {
+        if (mService == null) {
+            Log.e(TAG, "Can't get model state: not bound to SoundTriggerTestService");
+        } else {
+            mService.getModelState(mSelectedModelUuid);
+        }
+    }
+
     public synchronized void onCaptureAudioCheckboxClicked(View v) {
         // See if we have the right permissions
         if (!mService.hasMicrophonePermission()) {
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 380e299..6d4ffcf 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -23,6 +23,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
 import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -46,6 +48,7 @@
 import java.util.Random;
 import java.util.UUID;
 
+
 public class SoundTriggerTestService extends Service {
     private static final String TAG = "SoundTriggerTestSrv";
     private static final String INTENT_ACTION = "com.android.intent.action.MANAGE_SOUND_TRIGGER";
@@ -57,6 +60,8 @@
     private Random mRandom;
     private UserActivity mUserActivity;
 
+    private static int captureCount;
+
     public interface UserActivity {
         void addModel(UUID modelUuid, String state);
         void setModelState(UUID modelUuid, String state);
@@ -131,6 +136,8 @@
                         } else if (command.equals("set_capture_timeout")) {
                             setCaptureAudioTimeout(getModelUuidFromIntent(intent),
                                     intent.getIntExtra("timeout", 5000));
+                        } else if (command.equals("get_model_state")) {
+                            getModelState(getModelUuidFromIntent(intent));
                         } else {
                             Log.e(TAG, "Unknown command '" + command + "'");
                         }
@@ -432,6 +439,17 @@
         return modelInfo != null && modelInfo.captureAudioTrack != null;
     }
 
+    public synchronized void getModelState(UUID modelUuid) {
+        ModelInfo modelInfo = mModelInfoMap.get(modelUuid);
+        if (modelInfo == null) {
+            postError("Could not find model for: " + modelUuid.toString());
+            return;
+        }
+        int status = mSoundTriggerUtil.getModelState(modelUuid);
+        postMessage("GetModelState for: " + modelInfo.name + " returns: "
+            + status);
+    }
+
     private void loadModelsInDataDir() {
         // Load all the models in the data dir.
         boolean loadedModel = false;
@@ -527,18 +545,29 @@
         }
     }
 
+
     private class CaptureAudioRecorder implements Runnable {
         private final ModelInfo mModelInfo;
+
+        // EventPayload and RecognitionEvent are equivalant.  Only one will be non-null.
         private final SoundTriggerDetector.EventPayload mEvent;
+        private final RecognitionEvent mRecognitionEvent;
 
         public CaptureAudioRecorder(ModelInfo modelInfo, SoundTriggerDetector.EventPayload event) {
             mModelInfo = modelInfo;
             mEvent = event;
+            mRecognitionEvent = null;
+        }
+
+        public CaptureAudioRecorder(ModelInfo modelInfo, RecognitionEvent event) {
+            mModelInfo = modelInfo;
+            mEvent = null;
+            mRecognitionEvent = event;
         }
 
         @Override
         public void run() {
-            AudioFormat format = mEvent.getCaptureAudioFormat();
+            AudioFormat format = getAudioFormat();
             if (format == null) {
                 postErrorToast("No audio format in recognition event.");
                 return;
@@ -600,18 +629,21 @@
                 }
 
                 audioRecord = new AudioRecord(attributes, format, bytesRequired,
-                        mEvent.getCaptureSession());
+                        getCaptureSession());
 
                 byte[] buffer = new byte[bytesRequired];
 
                 // Create a file so we can save the output data there for analysis later.
                 FileOutputStream fos  = null;
                 try {
-                    fos = new FileOutputStream( new File(
-                            getFilesDir() + File.separator
-                                    + mModelInfo.name.replace(' ', '_')
-                                    + "_capture_" + format.getChannelCount() + "ch_"
-                                    + format.getSampleRate() + "hz_" + encoding + ".pcm"));
+                    File file = new File(
+                        getFilesDir() + File.separator
+                        + mModelInfo.name.replace(' ', '_')
+                        + "_capture_" + format.getChannelCount() + "ch_"
+                        + format.getSampleRate() + "hz_" + encoding
+                        + "_" + (++captureCount) + ".pcm");
+                    Log.i(TAG, "Writing audio to: " + file);
+                    fos = new FileOutputStream(file);
                 } catch (IOException e) {
                     Log.e(TAG, "Failed to open output for saving PCM data", e);
                     postErrorToast("Failed to open output for saving PCM data: "
@@ -635,6 +667,10 @@
                     bytesRequired -= bytesRead;
                 }
                 audioRecord.stop();
+                if (fos != null) {
+                  fos.flush();
+                  fos.close();
+                }
             } catch (Exception e) {
                 Log.e(TAG, "Error recording trigger audio", e);
                 postErrorToast("Error recording trigger audio: " + e.getMessage());
@@ -651,6 +687,26 @@
                 setModelState(mModelInfo, "Recording finished");
             }
         }
+
+        private AudioFormat getAudioFormat() {
+            if (mEvent != null) {
+                return mEvent.getCaptureAudioFormat();
+            }
+            if (mRecognitionEvent != null) {
+                return mRecognitionEvent.captureFormat;
+            }
+            return null;
+        }
+
+        private int getCaptureSession() {
+            if (mEvent != null) {
+                return mEvent.getCaptureSession();
+            }
+            if (mRecognitionEvent != null) {
+                return mRecognitionEvent.captureSession;
+            }
+            return 0;
+        }
     }
 
     // Implementation of SoundTriggerDetector.Callback.
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
index cfe8c85..996a78f 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -18,6 +18,8 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
 import android.media.soundtrigger.SoundTriggerDetector;
 import android.media.soundtrigger.SoundTriggerManager;
 import android.os.RemoteException;
@@ -27,6 +29,7 @@
 
 import com.android.internal.app.ISoundTriggerService;
 
+import java.lang.reflect.Method;
 import java.lang.RuntimeException;
 import java.util.UUID;
 
@@ -50,13 +53,31 @@
      * The sound model must contain a valid UUID.
      *
      * @param soundModel The sound model to add/update.
+     * @return The true if the model was loaded successfully, false otherwise.
      */
     public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) {
         if (soundModel == null) {
             throw new RuntimeException("Bad sound model");
         }
         mSoundTriggerManager.updateModel(soundModel);
-        return true;
+        // TODO: call loadSoundModel in the soundtrigger manager updateModel method
+        // instead of here. It is needed to keep soundtrigger manager internal
+        // state consistent.
+        return mSoundTriggerManager
+                .loadSoundModel(getGenericSoundModel(soundModel)) == 0;
+    }
+
+    private GenericSoundModel getGenericSoundModel(
+        SoundTriggerManager.Model soundModel) {
+        try {
+            Method method = SoundTriggerManager.Model.class
+                            .getDeclaredMethod("getGenericSoundModel");
+            method.setAccessible(true);
+            return (GenericSoundModel) method.invoke(soundModel);
+        } catch (ReflectiveOperationException e) {
+            Log.e(TAG, "Failed to getGenericSoundModel: " + soundModel, e);
+            return null;
+        }
     }
 
     /**
@@ -92,6 +113,16 @@
         return true;
     }
 
+    /**
+     * Get the current model state
+     *
+     * @param modelId The model ID to look-up the sound model for.
+     * @return 0 if the call succeeds, or an error code if it fails.
+     */
+    public int getModelState(UUID modelId) {
+        return mSoundTriggerManager.getModelState(modelId);
+    }
+
     public SoundTriggerDetector createSoundTriggerDetector(UUID modelId,
             SoundTriggerDetector.Callback callback) {
         return mSoundTriggerManager.createSoundTriggerDetector(modelId, callback, null);
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index e07fbbf..dc090aa 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -37,15 +37,19 @@
         "vts",
     ],
     data: [
-        ":NotoColorEmojiTtf",
+        ":NotoColorEmoji.ttf",
+        ":NotoSerif-Regular.ttf",
+        ":NotoSerif-Bold.ttf",
         ":UpdatableSystemFontTestCertDer",
-        ":UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
-        ":UpdatableSystemFontTestNotoColorEmojiV0Ttf",
-        ":UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
-        ":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
-        ":UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
-        ":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
-        ":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+        ":UpdatableSystemFontTest_NotoColorEmoji.sig",
+        ":UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
+        ":UpdatableSystemFontTest_NotoColorEmojiV0.sig",
+        ":UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
+        ":UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig",
+        ":UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
+        ":UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig",
+        ":UpdatableSystemFontTest_NotoSerif-Regular.sig",
+        ":UpdatableSystemFontTest_NotoSerif-Bold.sig",
     ],
     sdk_version: "test_current",
 }
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
index 4f6487e..6effa7b 100644
--- a/tests/UpdatableSystemFontTest/AndroidTest.xml
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -29,13 +29,17 @@
         <option name="cleanup" value="true" />
         <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
         <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf" />
-        <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />
+        <option name="push" value="NotoSerif-Regular.ttf->/data/local/tmp/NotoSerif-Regular.ttf" />
+        <option name="push" value="NotoSerif-Bold.ttf->/data/local/tmp/NotoSerif-Bold.ttf" />
+        <option name="push" value="UpdatableSystemFontTest_NotoSerif-Regular.sig->/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Regular.sig" />
+        <option name="push" value="UpdatableSystemFontTest_NotoSerif-Bold.sig->/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Bold.sig" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmoji.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmoji.sig" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiV0.ttf->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.ttf" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiV0.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.sig" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf" />
+        <option name="push" value="UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig->/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
index 947e9c2..a8c27fb0 100644
--- a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
@@ -20,6 +20,7 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import android.app.Activity;
+import android.graphics.Typeface;
 import android.os.Bundle;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -27,14 +28,20 @@
 /** Test app to render an emoji. */
 public class EmojiRenderingTestActivity extends Activity {
 
+    private static final String TEST_NOTO_SERIF = "test-noto-serif";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         LinearLayout container = new LinearLayout(this);
         container.setOrientation(LinearLayout.VERTICAL);
-        TextView textView = new TextView(this);
-        textView.setText("\uD83E\uDD72"); // 🥲
-        container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+        TextView emojiTextView = new TextView(this);
+        emojiTextView.setText("\uD83E\uDD72"); // 🥲
+        container.addView(emojiTextView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+        TextView serifTextView = new TextView(this);
+        serifTextView.setTypeface(Typeface.create(TEST_NOTO_SERIF, Typeface.NORMAL));
+        serifTextView.setText(TEST_NOTO_SERIF);
+        container.addView(serifTextView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
         setContentView(container);
     }
 }
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index 6bd07d0..87fda0d 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -16,6 +16,9 @@
 
 package com.android.updatablesystemfont;
 
+import static android.graphics.fonts.FontStyle.FONT_SLANT_UPRIGHT;
+import static android.graphics.fonts.FontStyle.FONT_WEIGHT_BOLD;
+import static android.graphics.fonts.FontStyle.FONT_WEIGHT_NORMAL;
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -30,6 +33,7 @@
 import android.graphics.fonts.FontFamilyUpdateRequest;
 import android.graphics.fonts.FontFileUpdateRequest;
 import android.graphics.fonts.FontManager;
+import android.graphics.fonts.FontStyle;
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.RootPermissionTest;
 import android.security.FileIntegrityManager;
@@ -77,31 +81,45 @@
     private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
     private static final String DATA_FONTS_DIR = "/data/fonts/files/";
     private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
-    private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";
 
-    private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF =
+    private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";
+    private static final String NOTO_COLOR_EMOJI_TTF =
             "/data/local/tmp/NotoColorEmoji.ttf";
-    private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig";
+    private static final String NOTO_COLOR_EMOJI_SIG =
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmoji.sig";
     // A font with revision == 0.
     private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf";
-    private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig";
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.ttf";
+    private static final String TEST_NOTO_COLOR_EMOJI_V0_SIG =
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiV0.sig";
     // A font with revision == original + 1
     private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf";
-    private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig";
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf";
+    private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG =
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig";
     // A font with revision == original + 2
     private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf";
-    private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG =
-            "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig";
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf";
+    private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG =
+            "/data/local/tmp/UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig";
+
+    private static final String NOTO_SERIF_REGULAR_POSTSCRIPT_NAME = "NotoSerif";
+    private static final String NOTO_SERIF_REGULAR_TTF =
+            "/data/local/tmp/NotoSerif-Regular.ttf";
+    private static final String NOTO_SERIF_REGULAR_SIG =
+            "/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Regular.sig";
+
+    private static final String NOTO_SERIF_BOLD_POSTSCRIPT_NAME = "NotoSerif-Bold";
+    private static final String NOTO_SERIF_BOLD_TTF =
+            "/data/local/tmp/NotoSerif-Bold.ttf";
+    private static final String NOTO_SERIF_BOLD_SIG =
+            "/data/local/tmp/UpdatableSystemFontTest_NotoSerif-Bold.sig";
 
     private static final String EMOJI_RENDERING_TEST_APP_ID = "com.android.emojirenderingtestapp";
     private static final String EMOJI_RENDERING_TEST_ACTIVITY =
             EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";
+    // This should be the same as the one in EmojiRenderingTestActivity.
+    private static final String TEST_NOTO_SERIF = "test-noto-serif";
     private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10);
 
     private static final String GET_AVAILABLE_FONTS_TEST_ACTIVITY =
@@ -141,11 +159,20 @@
 
     @Test
     public void updateFont() throws Exception {
+        FontConfig oldFontConfig =
+                SystemUtil.callWithShellPermissionIdentity(mFontManager::getFontConfig);
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
+        // Check that font config is updated.
         String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+        FontConfig newFontConfig =
+                SystemUtil.callWithShellPermissionIdentity(mFontManager::getFontConfig);
+        assertThat(newFontConfig.getConfigVersion())
+                .isGreaterThan(oldFontConfig.getConfigVersion());
+        assertThat(newFontConfig.getLastModifiedTimeMillis())
+                .isGreaterThan(oldFontConfig.getLastModifiedTimeMillis());
         // The updated font should be readable and unmodifiable.
         expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
         expectCommandToFail("dd status=none if=" + CERT_PATH + " of=" + fontPath);
@@ -154,11 +181,11 @@
     @Test
     public void updateFont_twice() throws Exception {
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
@@ -173,16 +200,16 @@
     public void updateFont_allowSameVersion() throws Exception {
         // Update original font to the same version
         assertThat(updateFontFile(
-                ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG))
+                NOTO_COLOR_EMOJI_TTF, NOTO_COLOR_EMOJI_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         // Update updated font to the same version
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(fontPath).startsWith(DATA_FONTS_DIR);
@@ -195,28 +222,58 @@
     @Test
     public void updateFont_invalidCert() throws Exception {
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG))
                 .isEqualTo(FontManager.RESULT_ERROR_VERIFICATION_FAILURE);
     }
 
     @Test
     public void updateFont_downgradeFromSystem() throws Exception {
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_SIG))
                 .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
     }
 
     @Test
     public void updateFont_downgradeFromData() throws Exception {
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                 .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
     }
 
     @Test
+    public void updateFontFamily() throws Exception {
+        assertThat(updateNotoSerifAs("serif")).isEqualTo(FontManager.RESULT_SUCCESS);
+        FontConfig.FontFamily family = findFontFamilyOrThrow("serif");
+        assertThat(family.getFontList()).hasSize(2);
+        assertThat(family.getFontList().get(0).getPostScriptName())
+                .isEqualTo(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME);
+        assertThat(family.getFontList().get(0).getFile().getAbsolutePath())
+                .startsWith(DATA_FONTS_DIR);
+        assertThat(family.getFontList().get(0).getStyle().getWeight())
+                .isEqualTo(FONT_WEIGHT_NORMAL);
+        assertThat(family.getFontList().get(1).getPostScriptName())
+                .isEqualTo(NOTO_SERIF_BOLD_POSTSCRIPT_NAME);
+        assertThat(family.getFontList().get(1).getFile().getAbsolutePath())
+                .startsWith(DATA_FONTS_DIR);
+        assertThat(family.getFontList().get(1).getStyle().getWeight()).isEqualTo(FONT_WEIGHT_BOLD);
+    }
+
+    @Test
+    public void updateFontFamily_asNewFont() throws Exception {
+        assertThat(updateNotoSerifAs("UpdatableSystemFontTest-serif"))
+                .isEqualTo(FontManager.RESULT_SUCCESS);
+        FontConfig.FontFamily family = findFontFamilyOrThrow("UpdatableSystemFontTest-serif");
+        assertThat(family.getFontList()).hasSize(2);
+        assertThat(family.getFontList().get(0).getPostScriptName())
+                .isEqualTo(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME);
+        assertThat(family.getFontList().get(1).getPostScriptName())
+                .isEqualTo(NOTO_SERIF_BOLD_POSTSCRIPT_NAME);
+    }
+
+    @Test
     public void launchApp() throws Exception {
         String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);
@@ -231,22 +288,25 @@
         String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
         assertThat(updateFontFile(
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                 .isEqualTo(FontManager.RESULT_SUCCESS);
         String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
+        updateNotoSerifAs(TEST_NOTO_SERIF);
+        String notoSerifPath = getFontPath(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME);
         startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);
         // The original font should NOT be opened by the app.
         SystemUtil.eventually(() -> {
             assertThat(isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue();
             assertThat(isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
+            assertThat(isFileOpenedBy(notoSerifPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue();
         }, ACTIVITY_TIMEOUT_MILLIS);
     }
 
     @Test
     public void reboot() throws Exception {
         expectCommandToSucceed(String.format("cmd font update %s %s",
-                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+                TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG));
         String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
         assertThat(fontPath).startsWith(DATA_FONTS_DIR);
 
@@ -264,7 +324,7 @@
                 Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
         for (int i = 0; i < 10; i++) {
             assertThat(updateFontFile(
-                    TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+                    TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG))
                     .isEqualTo(FontManager.RESULT_SUCCESS);
             List<String> openFiles = getOpenFiles("system_server");
             for (Pattern p : Arrays.asList(PATTERN_FONT_FILES, PATTERN_SYSTEM_FONT_FILES,
@@ -285,7 +345,7 @@
     public void fdLeakTest_withoutPermission() throws Exception {
         Pattern patternEmojiVPlus1 =
                 Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
-        byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+        byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_SIG));
         try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(
                 new File(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF), MODE_READ_ONLY)) {
             assertThrows(SecurityException.class,
@@ -340,18 +400,56 @@
                 configVersion);
     }
 
+    private int updateNotoSerifAs(String familyName) throws IOException {
+        List<FontFamilyUpdateRequest.Font> fonts = Arrays.asList(
+                new FontFamilyUpdateRequest.Font.Builder(NOTO_SERIF_REGULAR_POSTSCRIPT_NAME,
+                        new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT)).build(),
+                new FontFamilyUpdateRequest.Font.Builder(NOTO_SERIF_BOLD_POSTSCRIPT_NAME,
+                        new FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_UPRIGHT)).build());
+        FontFamilyUpdateRequest.FontFamily fontFamily =
+                new FontFamilyUpdateRequest.FontFamily.Builder(familyName, fonts).build();
+        byte[] regularSig = Files.readAllBytes(Paths.get(NOTO_SERIF_REGULAR_SIG));
+        byte[] boldSig = Files.readAllBytes(Paths.get(NOTO_SERIF_BOLD_SIG));
+        try (ParcelFileDescriptor regularFd = ParcelFileDescriptor.open(
+                    new File(NOTO_SERIF_REGULAR_TTF), MODE_READ_ONLY);
+             ParcelFileDescriptor boldFd = ParcelFileDescriptor.open(
+                    new File(NOTO_SERIF_BOLD_TTF), MODE_READ_ONLY)) {
+            return SystemUtil.runWithShellPermissionIdentity(() -> {
+                FontConfig fontConfig = mFontManager.getFontConfig();
+                return mFontManager.updateFontFamily(new FontFamilyUpdateRequest.Builder()
+                        .addFontFileUpdateRequest(
+                                new FontFileUpdateRequest(regularFd, regularSig))
+                        .addFontFileUpdateRequest(
+                                new FontFileUpdateRequest(boldFd, boldSig))
+                        .addFontFamily(fontFamily)
+                        .build(), fontConfig.getConfigVersion());
+            });
+        }
+    }
+
     private String getFontPath(String psName) {
-        return SystemUtil.runWithShellPermissionIdentity(() -> {
-            FontConfig fontConfig = mFontManager.getFontConfig();
-            for (FontConfig.FontFamily family : fontConfig.getFontFamilies()) {
-                for (FontConfig.Font font : family.getFontList()) {
-                    if (psName.equals(font.getPostScriptName())) {
-                        return font.getFile().getAbsolutePath();
-                    }
-                }
-            }
-            throw new AssertionError("Font not found: " + psName);
-        });
+        FontConfig fontConfig =
+                SystemUtil.runWithShellPermissionIdentity(mFontManager::getFontConfig);
+        return fontConfig.getFontFamilies().stream()
+                .flatMap(family -> family.getFontList().stream())
+                .filter(font -> psName.equals(font.getPostScriptName()))
+                // Return the last match, because the latter family takes precedence if two families
+                // have the same name.
+                .reduce((first, second) -> second)
+                .orElseThrow(() -> new AssertionError("Font not found: " + psName))
+                .getFile()
+                .getAbsolutePath();
+    }
+
+    private FontConfig.FontFamily findFontFamilyOrThrow(String familyName) {
+        FontConfig fontConfig =
+                SystemUtil.runWithShellPermissionIdentity(mFontManager::getFontConfig);
+        return fontConfig.getFontFamilies().stream()
+                .filter(family -> familyName.equals(family.getName()))
+                // Return the last match, because the latter family takes precedence if two families
+                // have the same name.
+                .reduce((first, second) -> second)
+                .orElseThrow(() -> new AssertionError("Family not found: " + familyName));
     }
 
     private static void startActivity(String appId, String activityId) throws Exception {
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
index 0f01be0..1e6cb5e 100644
--- a/tests/UpdatableSystemFontTest/testdata/Android.bp
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -41,9 +41,9 @@
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiV0Ttf",
-    srcs: [":NotoColorEmojiTtf"],
-    out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf"],
+    name: "UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
+    srcs: [":NotoColorEmoji.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmojiV0.ttf"],
     tools: ["update_font_metadata"],
     cmd: "$(location update_font_metadata) " +
         "--input=$(in) " +
@@ -52,9 +52,9 @@
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
-    srcs: [":NotoColorEmojiTtf"],
-    out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf"],
+    name: "UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
+    srcs: [":NotoColorEmoji.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf"],
     tools: ["update_font_metadata"],
     cmd: "$(location update_font_metadata) " +
         "--input=$(in) " +
@@ -63,9 +63,9 @@
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
-    srcs: [":NotoColorEmojiTtf"],
-    out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf"],
+    name: "UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
+    srcs: [":NotoColorEmoji.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf"],
     tools: ["update_font_metadata"],
     cmd: "$(location update_font_metadata) " +
         "--input=$(in) " +
@@ -87,29 +87,43 @@
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
+    name: "UpdatableSystemFontTest_NotoColorEmoji.sig",
     defaults: ["updatable_system_font_sig_gen_default"],
-    srcs: [":NotoColorEmojiTtf"],
-    out: ["UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig"],
+    srcs: [":NotoColorEmoji.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmoji.sig"],
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
+    name: "UpdatableSystemFontTest_NotoColorEmojiV0.sig",
     defaults: ["updatable_system_font_sig_gen_default"],
-    srcs: [":UpdatableSystemFontTestNotoColorEmojiV0Ttf"],
-    out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmojiV0.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmojiV0.sig"],
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
+    name: "UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig",
     defaults: ["updatable_system_font_sig_gen_default"],
-    srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf"],
-    out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig"],
 }
 
 genrule {
-    name: "UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+    name: "UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig",
     defaults: ["updatable_system_font_sig_gen_default"],
-    srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf"],
-    out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf"],
+    out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig"],
+}
+
+genrule {
+    name: "UpdatableSystemFontTest_NotoSerif-Regular.sig",
+    defaults: ["updatable_system_font_sig_gen_default"],
+    srcs: [":NotoSerif-Regular.ttf"],
+    out: ["UpdatableSystemFontTest_NotoSerif-Regular.sig"],
+}
+
+genrule {
+    name: "UpdatableSystemFontTest_NotoSerif-Bold.sig",
+    defaults: ["updatable_system_font_sig_gen_default"],
+    srcs: [":NotoSerif-Bold.ttf"],
+    out: ["UpdatableSystemFontTest_NotoSerif-Bold.sig"],
 }
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index bcd6ed7..824f91e 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -45,6 +45,7 @@
             // Test specifications for FrameworksMockingCoreTests.
             "android.app.activity.ActivityThreadClientTest",
             "android.view.DisplayTest",
+            "android.window.ConfigurationHelperTest",
             // Test specifications for FrameworksCoreTests.
             "android.app.servertransaction.", // all tests under the package.
             "android.view.CutoutSpecificationTest",
@@ -59,10 +60,8 @@
             "android.view.RoundedCornersTest",
             "android.view.WindowMetricsTest",
             "android.view.PendingInsetsControllerTest",
-            "android.window.WindowContextTest",
-            "android.window.WindowMetricsHelperTest",
+            "android.window.", // all tests under the package.
             "android.app.activity.ActivityThreadTest",
-            "android.window.WindowContextControllerTest"
     };
 
     public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/tests/vcn/OWNERS b/tests/vcn/OWNERS
index 33b9f0f..2441e77 100644
--- a/tests/vcn/OWNERS
+++ b/tests/vcn/OWNERS
@@ -3,5 +3,5 @@
 benedictwong@google.com
 ckesting@google.com
 evitayan@google.com
+junyin@google.com
 nharold@google.com
-jchalard@google.com
\ No newline at end of file
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 96f6512..ebe41da 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@
 
 static ApiVersion sDevelopmentSdkLevel = 10000;
 static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>({
-    "Q", "R", "S"
+    "Q", "R", "S", "T"
 });
 
 static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 81d35ef..3cdb27c 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -8,7 +8,21 @@
     # Change is explicitly marked as ok to skip AOSP
     exit 0
 else
-    # Change appears to be non-AOSP; search for files
+    # Change appears to be non-AOSP.
+
+    # If this is a cherry-pick, then allow it.
+    cherrypick=0
+    while read -r line ; do
+      if [[ $line =~ cherry\ picked\ from  ]] ; then
+        (( cherrypick++ ))
+      fi
+    done < <(git show $1)
+    if (( cherrypick != 0 )); then
+      # This is a cherry-pick, so allow it.
+      exit 0
+    fi
+
+    # See if any files are affected.
     count=0
     while read -r file ; do
         if (( count == 0 )); then
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index 7cfa784..9ceb204 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -43,8 +43,8 @@
  * cccc dd
  */
 fun Iterable<Pair<String, String>>.columnize(separator: String = " | "): String {
-    val col1w = map { (a, _) -> a.length }.max()!!
-    val col2w = map { (_, b) -> b.length }.max()!!
+    val col1w = map { (a, _) -> a.length }.maxOrNull()!!
+    val col2w = map { (_, b) -> b.length }.maxOrNull()!!
     return map { it.first.padEnd(col1w) + separator + it.second.padEnd(col2w) }.joinToString("\n")
 }
 
diff --git a/tools/lint/Android.bp b/tools/lint/Android.bp
new file mode 100644
index 0000000..dcbc32b
--- /dev/null
+++ b/tools/lint/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // 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_host {
+    name: "AndroidFrameworkLintChecker",
+    srcs: ["checks/src/main/java/**/*.kt"],
+    plugins: ["auto_service_plugin"],
+    libs: [
+        "auto_service_annotations",
+        "lint_api",
+    ],
+}
+
+// TODO: (b/162368644) Implement these (working in gradle) Kotlin Tests to run on Soong
+//java_test_host {
+//    name: "AndroidFrameworkLintCheckerTest",
+//    srcs: [
+//     "checks/src/test/java/**/*.kt",
+//     "checks/src/main/java/**/*.kt",
+//    ],
+//    plugins: ["auto_service_plugin"],
+//    static_libs: [
+//        "auto_service_annotations",
+//        "lint_api",
+//    ],
+//}
diff --git a/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenDetector.kt b/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenDetector.kt
new file mode 100644
index 0000000..4e30834
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenDetector.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.lint
+
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_NESTED_CLEAR_IDENTITY_CALLS
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_NON_FINAL_TOKEN
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_UNUSED_TOKEN
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageNestedClearIdentityCallsPrimary
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageNestedClearIdentityCallsSecondary
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageNonFinalToken
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageRestoreIdentityCallNotInFinallyBlock
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageUnusedToken
+import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.search.PsiSearchScopeUtil
+import com.intellij.psi.search.SearchScope
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.ULocalVariable
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.USimpleNameReferenceExpression
+import org.jetbrains.uast.UTryExpression
+import org.jetbrains.uast.getParentOfType
+import org.jetbrains.uast.isUastChildOf
+
+/**
+ * Lint Detector that finds issues with improper usages of the token returned by
+ * Binder.clearCallingIdentity()
+ */
+@Suppress("UnstableApiUsage")
+class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
+    private companion object {
+        const val CLASS_BINDER = "android.os.Binder"
+        const val CLASS_USER_HANDLE = "android.os.UserHandle"
+
+        @JvmField
+        val callerAwareMethods = listOf(
+                Method.BINDER_GET_CALLING_PID,
+                Method.BINDER_GET_CALLING_UID,
+                Method.BINDER_GET_CALLING_UID_OR_THROW,
+                Method.BINDER_GET_CALLING_USER_HANDLE,
+                Method.USER_HANDLE_GET_CALLING_APP_ID,
+                Method.USER_HANDLE_GET_CALLING_USER_ID
+        )
+    }
+
+    /** Map of <Token variable name, Token object> */
+    private val tokensMap = mutableMapOf<String, Token>()
+
+    override fun getApplicableUastTypes(): List<Class<out UElement?>> =
+            listOf(ULocalVariable::class.java, UQualifiedReferenceExpression::class.java)
+
+    override fun createUastHandler(context: JavaContext): UElementHandler =
+            TokenUastHandler(context)
+
+    /** File analysis starts with a clear map */
+    override fun beforeCheckFile(context: Context) {
+        tokensMap.clear()
+    }
+
+    /**
+     * - If tokensMap has tokens after checking the file -> reports all locations as unused token
+     * issue incidents
+     * - File analysis ends with a clear map
+     */
+    override fun afterCheckFile(context: Context) {
+        for (token in tokensMap.values) {
+            context.report(
+                    ISSUE_UNUSED_TOKEN,
+                    token.location,
+                    getIncidentMessageUnusedToken(token.variableName)
+            )
+        }
+        tokensMap.clear()
+    }
+
+    /** UAST handler that analyses elements and reports incidents */
+    private inner class TokenUastHandler(val context: JavaContext) : UElementHandler() {
+        /**
+         * For every variable initialization with Binder.clearCallingIdentity():
+         * - Checks for non-final token issue
+         * - Checks for unused token issue within different scopes
+         * - Checks for nested calls of clearCallingIdentity() issue
+         * - Stores token variable name, scope in the file and its location in tokensMap
+         */
+        override fun visitLocalVariable(node: ULocalVariable) {
+            val rhsExpression = node.uastInitializer as? UQualifiedReferenceExpression ?: return
+            if (!isMethodCall(rhsExpression, Method.BINDER_CLEAR_CALLING_IDENTITY)) return
+            val location = context.getLocation(node as UElement)
+            val variableName = node.getName()
+            if (!node.isFinal) {
+                context.report(
+                        ISSUE_NON_FINAL_TOKEN,
+                        location,
+                        getIncidentMessageNonFinalToken(variableName)
+                )
+            }
+            // If there exists an unused variable with the same name in the map, we can imply that
+            // we left the scope of the previous declaration, so we need to report the unused token
+            val oldToken = tokensMap[variableName]
+            if (oldToken != null) {
+                context.report(
+                        ISSUE_UNUSED_TOKEN,
+                        oldToken.location,
+                        getIncidentMessageUnusedToken(oldToken.variableName)
+                )
+            }
+            // If there exists a token in the same scope as the current new token, it means that
+            // clearCallingIdentity() has been called at least twice without immediate restoration
+            // of identity, so we need to report the nested call of clearCallingIdentity()
+            val firstCallToken = findFirstTokenInScope(node)
+            if (firstCallToken != null) {
+                context.report(
+                        ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+                        createNestedLocation(firstCallToken, location),
+                        getIncidentMessageNestedClearIdentityCallsPrimary(
+                                firstCallToken.variableName,
+                                variableName
+                        )
+                )
+            }
+            tokensMap[variableName] = Token(variableName, node.sourcePsi?.getUseScope(), location)
+        }
+
+        /**
+         * For every class.method():
+         * - Checks use of caller-aware methods issue
+         * For every call of Binder.restoreCallingIdentity(token):
+         * - Checks for restoreCallingIdentity() not in the finally block issue
+         * - Removes token from tokensMap if token is within the scope of the method
+         */
+        override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) {
+            val token = findFirstTokenInScope(node)
+            if (isCallerAwareMethod(node) && token != null) {
+                context.report(
+                        ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+                        context.getLocation(node),
+                        getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
+                                token.variableName,
+                                node.asRenderString()
+                        )
+                )
+                return
+            }
+            if (!isMethodCall(node, Method.BINDER_RESTORE_CALLING_IDENTITY)) return
+            val selector = node.selector as UCallExpression
+            val arg = selector.valueArguments[0] as? USimpleNameReferenceExpression ?: return
+            val variableName = arg.identifier
+            if (!isInFinallyBlock(node)) {
+                context.report(
+                        ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+                        context.getLocation(node),
+                        getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName)
+                )
+            }
+            val originalScope = tokensMap[variableName]?.scope ?: return
+            val psi = arg.sourcePsi ?: return
+            if (PsiSearchScopeUtil.isInScope(originalScope, psi)) {
+                tokensMap.remove(variableName)
+            }
+        }
+
+        private fun isCallerAwareMethod(expression: UQualifiedReferenceExpression): Boolean =
+                callerAwareMethods.any { method -> isMethodCall(expression, method) }
+
+        private fun isMethodCall(
+            expression: UQualifiedReferenceExpression,
+            method: Method
+        ): Boolean {
+            val psiMethod = expression.resolve() as? PsiMethod ?: return false
+            return psiMethod.getName() == method.methodName &&
+                    context.evaluator.methodMatches(
+                            psiMethod,
+                            method.className,
+                            /* allowInherit */ true,
+                            *method.args
+                    )
+        }
+    }
+
+    private fun isInFinallyBlock(expression: UExpression): Boolean {
+        val tryExpression = expression.getParentOfType<UTryExpression>(strict = true)
+                ?: return false
+        return expression.isUastChildOf(tryExpression.finallyClause)
+    }
+
+    private fun findFirstTokenInScope(node: UElement): Token? {
+        val psi = node.sourcePsi ?: return null
+        for (token in tokensMap.values) {
+            if (token.scope != null && PsiSearchScopeUtil.isInScope(token.scope, psi)) {
+                return token
+            }
+        }
+        return null
+    }
+
+    /**
+     * Creates a new instance of the primary location with the secondary location
+     *
+     * Here, secondary location is the helper location that shows where the issue originated
+     *
+     * The detector reports locations as objects, so when we add a secondary location to a location
+     * that has multiple issues, the secondary location gets displayed every time a location is
+     * referenced.
+     *
+     * Example:
+     * 1: final long token1 = Binder.clearCallingIdentity();
+     * 2: long token2 = Binder.clearCallingIdentity();
+     * 3: Binder.restoreCallingIdentity(token1);
+     * 4: Binder.restoreCallingIdentity(token2);
+     *
+     * Explanation:
+     * token2 has 2 issues: NonFinal and NestedCalls
+     *
+     *     Lint report without cloning                        Lint report with cloning
+     * line 2: [NonFinalIssue]                            line 2: [NonFinalIssue]
+     *     line 1: [NestedCallsIssue]
+     * line 2: [NestedCallsIssue]                            line 2: [NestedCallsIssue]
+     *     line 1: [NestedCallsIssue]                           line 1: [NestedCallsIssue]
+     */
+    private fun createNestedLocation(
+        firstCallToken: Token,
+        secondCallTokenLocation: Location
+    ): Location {
+        return cloneLocation(secondCallTokenLocation)
+                .withSecondary(
+                        cloneLocation(firstCallToken.location),
+                        getIncidentMessageNestedClearIdentityCallsSecondary(
+                                firstCallToken.variableName
+                        )
+                )
+    }
+
+    private fun cloneLocation(location: Location): Location {
+        // smart cast of location.start to 'Position' is impossible, because 'location.start' is a
+        // public API property declared in different module
+        val locationStart = location.start
+        return if (locationStart == null) {
+            Location.create(location.file)
+        } else {
+            Location.create(location.file, locationStart, location.end)
+        }
+    }
+
+    private enum class Method(
+        val className: String,
+        val methodName: String,
+        val args: Array<String>
+    ) {
+        BINDER_CLEAR_CALLING_IDENTITY(CLASS_BINDER, "clearCallingIdentity", emptyArray()),
+        BINDER_RESTORE_CALLING_IDENTITY(CLASS_BINDER, "restoreCallingIdentity", arrayOf("long")),
+        BINDER_GET_CALLING_PID(CLASS_BINDER, "getCallingPid", emptyArray()),
+        BINDER_GET_CALLING_UID(CLASS_BINDER, "getCallingUid", emptyArray()),
+        BINDER_GET_CALLING_UID_OR_THROW(CLASS_BINDER, "getCallingUidOrThrow", emptyArray()),
+        BINDER_GET_CALLING_USER_HANDLE(CLASS_BINDER, "getCallingUserHandle", emptyArray()),
+        USER_HANDLE_GET_CALLING_APP_ID(CLASS_USER_HANDLE, "getCallingAppId", emptyArray()),
+        USER_HANDLE_GET_CALLING_USER_ID(CLASS_USER_HANDLE, "getCallingUserId", emptyArray())
+    }
+
+    private data class Token(
+        val variableName: String,
+        val scope: SearchScope?,
+        val location: Location
+    )
+}
diff --git a/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenIssueRegistry.kt b/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenIssueRegistry.kt
new file mode 100644
index 0000000..a0e9249
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenIssueRegistry.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.lint
+
+import com.android.tools.lint.client.api.IssueRegistry
+// TODO: uncomment when lint API in Soong becomes 30.0+
+// import com.android.tools.lint.client.api.Vendor
+import com.android.tools.lint.detector.api.CURRENT_API
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.google.auto.service.AutoService
+
+@AutoService(IssueRegistry::class)
+@Suppress("UnstableApiUsage")
+class CallingIdentityTokenIssueRegistry : IssueRegistry() {
+    override val issues = listOf(
+            ISSUE_UNUSED_TOKEN,
+            ISSUE_NON_FINAL_TOKEN,
+            ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+            ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+            ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY
+    )
+
+    override val api: Int
+        get() = CURRENT_API
+
+    override val minApi: Int
+        get() = 8
+
+//    TODO: uncomment when lint API in Soong becomes 30.0+
+//    override val vendor: Vendor = Vendor(
+//            vendorName = "Android Open Source Project",
+//            feedbackUrl = "http://b/issues/new?component=315013",
+//            contact = "brufino@google.com"
+//    )
+
+    companion object {
+        /** Issue: unused token from Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_UNUSED_TOKEN: Issue = Issue.create(
+                id = "UnusedTokenOfOriginalCallingIdentity",
+                briefDescription = "Unused token of Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but have not used the returned token to \
+                    restore the identity.
+
+                    Call `Binder.restoreCallingIdentity(token)` in the `finally` block, at the end \
+                    of the method or when you need to restore the identity.
+
+                    `token` is the result of `Binder.clearCallingIdentity()`
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        fun getIncidentMessageUnusedToken(variableName: String) = "`$variableName` has not been " +
+                "used to restore the calling identity. Call " +
+                "`Binder.restoreCallingIdentity($variableName)` or remove `$variableName`."
+
+        /** Issue: non-final token from Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_NON_FINAL_TOKEN: Issue = Issue.create(
+                id = "NonFinalTokenOfOriginalCallingIdentity",
+                briefDescription = "Non-final token of Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but have not made the returned token `final`.
+
+                    The token should be `final` in order to prevent it from being overwritten, \
+                    which can cause problems when restoring the identity with \
+                    `Binder.restoreCallingIdentity(token)`.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        fun getIncidentMessageNonFinalToken(variableName: String) = "`$variableName` is a " +
+                "non-final token from `Binder.clearCallingIdentity()`. Add `final` keyword to " +
+                "`$variableName`."
+
+        /** Issue: nested calls of Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_NESTED_CLEAR_IDENTITY_CALLS: Issue = Issue.create(
+                id = "NestedClearCallingIdentityCalls",
+                briefDescription = "Nested calls of Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()` twice without restoring identity with the \
+                    result of the first call.
+
+                    Make sure to restore the identity after each clear identity call.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        fun getIncidentMessageNestedClearIdentityCallsPrimary(
+            firstCallVariableName: String,
+            secondCallVariableName: String
+        ): String = "The calling identity has already been cleared and returned into " +
+                "`$firstCallVariableName`. Move `$secondCallVariableName` declaration after " +
+                "restoring the calling identity with " +
+                "`Binder.restoreCallingIdentity($firstCallVariableName)`."
+
+        fun getIncidentMessageNestedClearIdentityCallsSecondary(
+            firstCallVariableName: String
+        ): String = "Location of the `$firstCallVariableName` declaration."
+
+        /** Issue: Binder.restoreCallingIdentity() is not in finally block */
+        @JvmField
+        val ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK: Issue = Issue.create(
+                id = "RestoreIdentityCallNotInFinallyBlock",
+                briefDescription = "Binder.restoreCallingIdentity() is not in finally block",
+                explanation = """
+                    You are restoring the original calling identity with \
+                    `Binder.restoreCallingIdentity()`, but the call is not in the `finally` block \
+                    of the `try` statement.
+
+                    Use the following pattern for running operations with your own identity:
+
+                    ```
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        // Code using your own identity
+                    } finally {
+                        Binder.restoreCallingIdentity();
+                    }
+                    ```
+
+                    If you do not surround the code using your identity with the `try` statement \
+                    and call `Binder.restoreCallingIdentity()` in the `finally` block, you may run \
+                    code with your identity that was originally intended to run with the calling \
+                    application's identity.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        fun getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName: String): String =
+                "`Binder.restoreCallingIdentity($variableName)` is not in the `finally` block. " +
+                        "Surround the call with `finally` block."
+
+        /** Issue: Use of caller-aware methods after Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY: Issue = Issue.create(
+                id = "UseOfCallerAwareMethodsWithClearedIdentity",
+                briefDescription = "Use of caller-aware methods after " +
+                        "Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but used one of the methods below before \
+                    restoring the identity. These methods will use your own identity instead of \
+                    the caller's identity, so if this is expected replace them with methods that \
+                    explicitly query your own identity such as `Process.myUid()`, \
+                    `Process.myPid()` and `UserHandle.myUserId()`, otherwise move those methods \
+                    out of the `Binder.clearCallingIdentity()` / `Binder.restoreCallingIdentity()` \
+                    section.
+
+                    ```
+                    Binder.getCallingPid()
+                    Binder.getCallingUid()
+                    Binder.getCallingUidOrThrow()
+                    Binder.getCallingUserHandle()
+                    UserHandle.getCallingAppId()
+                    UserHandle.getCallingUserId()
+                    ```
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        fun getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
+            variableName: String,
+            methodName: String
+        ): String = "You cleared the original identity with `Binder.clearCallingIdentity()` " +
+                "and returned into `$variableName`, so `$methodName` will be using your own " +
+                "identity instead of the caller's. Either explicitly query your own identity or " +
+                "move it after restoring the identity with " +
+                "`Binder.restoreCallingIdentity($variableName)`."
+    }
+}
diff --git a/tools/lint/checks/src/test/java/com/android/lint/CallingIdentityTokenDetectorTest.kt b/tools/lint/checks/src/test/java/com/android/lint/CallingIdentityTokenDetectorTest.kt
new file mode 100644
index 0000000..8a81609
--- /dev/null
+++ b/tools/lint/checks/src/test/java/com/android/lint/CallingIdentityTokenDetectorTest.kt
@@ -0,0 +1,747 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class CallingIdentityTokenDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = CallingIdentityTokenDetector()
+
+    override fun getIssues(): List<Issue> = listOf(
+            CallingIdentityTokenIssueRegistry.ISSUE_UNUSED_TOKEN,
+            CallingIdentityTokenIssueRegistry.ISSUE_NON_FINAL_TOKEN,
+            CallingIdentityTokenIssueRegistry.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+            CallingIdentityTokenIssueRegistry.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+            CallingIdentityTokenIssueRegistry
+                    .ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY
+    )
+
+    /** No issue scenario */
+
+    fun testDoesNotDetectIssuesInCorrectScenario() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            final long token1 = Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                Binder.restoreCallingIdentity(token1);
+                            }
+                            final long token2 = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token2);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    /** Unused token issue tests */
+
+    fun testDetectsUnusedTokens() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod1() {
+                            final long token1 = Binder.clearCallingIdentity();
+                        }
+                        private void testMethod2() {
+                            final long token2 = android.os.Binder.clearCallingIdentity();
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: token1 has not been used to \
+                        restore the calling identity. Call Binder.restoreCallingIdentity(token1) \
+                        or remove token1. [UnusedTokenOfOriginalCallingIdentity]
+                                final long token1 = Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:8: Warning: token2 has not been used to \
+                        restore the calling identity. Call Binder.restoreCallingIdentity(token2) \
+                        or remove token2. [UnusedTokenOfOriginalCallingIdentity]
+                                final long token2 = android.os.Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDetectsUnusedTokensInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod1() {
+                            final long token = Binder.clearCallingIdentity();
+                        }
+                        private void testMethod2() {
+                            long token = 0;
+                            try {
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: token has not been used to \
+                        restore the calling identity. Call Binder.restoreCallingIdentity(token) \
+                        or remove token. [UnusedTokenOfOriginalCallingIdentity]
+                                final long token = Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 1 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDoesNotDetectUsedTokensInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod1() {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                        private void testMethod2() {
+                            long token = 0;
+                            try {
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testDetectsUnusedTokensWithSimilarNamesInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod1() {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                            }
+                        }
+                        private void testMethod2() {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: token has not been used to \
+                        restore the calling identity. Call Binder.restoreCallingIdentity(token) \
+                        or remove token. [UnusedTokenOfOriginalCallingIdentity]
+                                final long token = Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:11: Warning: token has not been used to \
+                        restore the calling identity. Call Binder.restoreCallingIdentity(token) \
+                        or remove token. [UnusedTokenOfOriginalCallingIdentity]
+                                final long token = Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    /** Non-final token issue tests */
+
+    fun testDetectsNonFinalTokens() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            long token1 = Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                Binder.restoreCallingIdentity(token1);
+                            }
+                            long token2 = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token2);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: token1 is a non-final token from \
+                        Binder.clearCallingIdentity(). Add final keyword to token1. \
+                        [NonFinalTokenOfOriginalCallingIdentity]
+                                long token1 = Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:10: Warning: token2 is a non-final token from \
+                        Binder.clearCallingIdentity(). Add final keyword to token2. \
+                        [NonFinalTokenOfOriginalCallingIdentity]
+                                long token2 = android.os.Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    /** Nested clearCallingIdentity() calls issue tests */
+
+    fun testDetectsNestedClearCallingIdentityCallsPattern1() {
+        // Pattern: clear - clear - restore - clear - restore - restore
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            final long token1 = Binder.clearCallingIdentity();
+                            final long token2 = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token1);
+                            }
+                            final long token3 = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token2);
+                            }
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token3);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:6: Warning: The calling identity has already \
+                        been cleared and returned into token1. Move token2 declaration after \
+                        restoring the calling identity with Binder.restoreCallingIdentity(token1). \
+                        [NestedClearCallingIdentityCalls]
+                                final long token2 = android.os.Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                            src/test/pkg/TestClass1.java:5: Location of the token1 declaration.
+                        src/test/pkg/TestClass1.java:11: Warning: The calling identity has already \
+                        been cleared and returned into token2. Move token3 declaration after \
+                        restoring the calling identity with Binder.restoreCallingIdentity(token2). \
+                        [NestedClearCallingIdentityCalls]
+                                final long token3 = android.os.Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                            src/test/pkg/TestClass1.java:6: Location of the token2 declaration.
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDetectsNestedClearCallingIdentityCallsPattern2() {
+        // Pattern: clear - clear - clear - restore - restore - restore
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            final long token1 = Binder.clearCallingIdentity();
+                            final long token2 = android.os.Binder.clearCallingIdentity();
+                            final long token3 = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                Binder.restoreCallingIdentity(token1);
+                            }
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token2);
+                            }
+                            try {
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token3);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:6: Warning: The calling identity has already \
+                        been cleared and returned into token1. Move token2 declaration after \
+                        restoring the calling identity with Binder.restoreCallingIdentity(token1). \
+                        [NestedClearCallingIdentityCalls]
+                                final long token2 = android.os.Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                            src/test/pkg/TestClass1.java:5: Location of the token1 declaration.
+                        src/test/pkg/TestClass1.java:7: Warning: The calling identity has already \
+                        been cleared and returned into token1. Move token3 declaration after \
+                        restoring the calling identity with Binder.restoreCallingIdentity(token1). \
+                        [NestedClearCallingIdentityCalls]
+                                final long token3 = android.os.Binder.clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                            src/test/pkg/TestClass1.java:5: Location of the token1 declaration.
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDetectsNestedClearCallingIdentityCallsInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            final long token1 = Binder.clearCallingIdentity();
+                            try {
+                                final long token2 = android.os.Binder.clearCallingIdentity();
+                                try {
+                                } finally {
+                                    Binder.restoreCallingIdentity(token2);
+                                }
+                            } finally {
+                                android.os.Binder.restoreCallingIdentity(token1);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:7: Warning: The calling identity has already \
+                        been cleared and returned into token1. Move token2 declaration after \
+                        restoring the calling identity with Binder.restoreCallingIdentity(token1). \
+                        [NestedClearCallingIdentityCalls]
+                                    final long token2 = android.os.Binder.clearCallingIdentity();
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                            src/test/pkg/TestClass1.java:5: Location of the token1 declaration.
+                        0 errors, 1 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    /** restoreCallingIdentity() call not in finally block issue tests */
+
+    fun testDetectsRestoreCallingIdentityCallNotInFinally() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod1() {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                            } catch (Exception e) {
+                            }
+                            Binder.restoreCallingIdentity(token);
+                            }
+                            private void testMethod2() {
+                            final long token = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                            }
+                            android.os.Binder.restoreCallingIdentity(token);
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:9: Warning: \
+                        Binder.restoreCallingIdentity(token) is not in the finally block. Surround \
+                        the call with finally block. [RestoreIdentityCallNotInFinallyBlock]
+                                Binder.restoreCallingIdentity(token);
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:16: Warning: \
+                        Binder.restoreCallingIdentity(token) is not in the finally block. Surround \
+                        the call with finally block. [RestoreIdentityCallNotInFinallyBlock]
+                                android.os.Binder.restoreCallingIdentity(token);
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDetectsRestoreCallingIdentityCallNotInFinallyInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod1() {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                            } catch (Exception e) {
+                            }
+                            {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                        private void testMethod2() {
+                            final long token = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                            }
+                            {
+                                {
+                                    {
+                                        android.os.Binder.restoreCallingIdentity(token);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:10: Warning: \
+                        Binder.restoreCallingIdentity(token) is not in the finally block. Surround \
+                        the call with finally block. [RestoreIdentityCallNotInFinallyBlock]
+                                    Binder.restoreCallingIdentity(token);
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:21: Warning: \
+                        Binder.restoreCallingIdentity(token) is not in the finally block. Surround \
+                        the call with finally block. [RestoreIdentityCallNotInFinallyBlock]
+                                            android.os.Binder.restoreCallingIdentity(token);
+                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDoesNotDetectRestoreCallingIdentityCallInFinallyInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            final long token1 = Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                {
+                                    {
+                                        Binder.restoreCallingIdentity(token1);
+                                    }
+                                }
+                            }
+                            final long token2 = android.os.Binder.clearCallingIdentity();
+                            try {
+                            } finally {
+                                {
+                                    {
+                                        android.os.Binder.restoreCallingIdentity(token2);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    /** Use of caller-aware methods after clearCallingIdentity() issue tests */
+
+    fun testDetectsUseOfCallerAwareMethodsWithClearedIdentityIssuesInScopes() {
+        lint().files(
+                java(
+                    """
+                    package test.pkg;
+                    import android.os.Binder;
+                    import android.os.UserHandle;
+                    public class TestClass1 {
+                        private void testMethod() {
+                            final long token = Binder.clearCallingIdentity();
+                            int pid1 = Binder.getCallingPid();
+                            int pid2 = android.os.Binder.getCallingPid();
+                            int uid1 = Binder.getCallingUid();
+                            int uid2 = android.os.Binder.getCallingUid();
+                            try {
+                                int uid3 = Binder.getCallingUidOrThrow();
+                                int uid4 = android.os.Binder.getCallingUidOrThrow();
+                                UserHandle uh1 = Binder.getCallingUserHandle();
+                                UserHandle uh2 = android.os.Binder.getCallingUserHandle();
+                                {
+                                    int appId1 = UserHandle.getCallingAppId();
+                                    int appId2 = android.os.UserHandle.getCallingAppId();
+                                    int userId1 = UserHandle.getCallingUserId();
+                                    int userId2 = android.os.UserHandle.getCallingUserId();
+                                }
+                            } finally {
+                            Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:7: Warning: You cleared the original identity \
+                        with Binder.clearCallingIdentity() and returned into token, so \
+                        Binder.getCallingPid() will be using your own identity instead of the \
+                        caller's. Either explicitly query your own identity or move it after \
+                        restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                int pid1 = Binder.getCallingPid();
+                                           ~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:8: Warning: You cleared the original identity \
+                        with Binder.clearCallingIdentity() and returned into token, so \
+                        android.os.Binder.getCallingPid() will be using your own identity instead \
+                        of the caller's. Either explicitly query your own identity or move it \
+                        after restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                int pid2 = android.os.Binder.getCallingPid();
+                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:9: Warning: You cleared the original identity \
+                        with Binder.clearCallingIdentity() and returned into token, so \
+                        Binder.getCallingUid() will be using your own identity instead of the \
+                        caller's. Either explicitly query your own identity or move it after \
+                        restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                int uid1 = Binder.getCallingUid();
+                                           ~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:10: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        android.os.Binder.getCallingUid() will be using your own identity instead \
+                        of the caller's. Either explicitly query your own identity or move it \
+                        after restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                int uid2 = android.os.Binder.getCallingUid();
+                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:12: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        Binder.getCallingUidOrThrow() will be using your own identity instead of \
+                        the caller's. Either explicitly query your own identity or move it after \
+                        restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                    int uid3 = Binder.getCallingUidOrThrow();
+                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:13: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        android.os.Binder.getCallingUidOrThrow() will be using your own identity \
+                        instead of the caller's. Either explicitly query your own identity or move \
+                        it after restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                    int uid4 = android.os.Binder.getCallingUidOrThrow();
+                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:14: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        Binder.getCallingUserHandle() will be using your own identity instead of \
+                        the caller's. Either explicitly query your own identity or move it after \
+                        restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                    UserHandle uh1 = Binder.getCallingUserHandle();
+                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:15: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        android.os.Binder.getCallingUserHandle() will be using your own identity \
+                        instead of the caller's. Either explicitly query your own identity or move \
+                        it after restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                    UserHandle uh2 = android.os.Binder.getCallingUserHandle();
+                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:17: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        UserHandle.getCallingAppId() will be using your own identity instead of \
+                        the caller's. Either explicitly query your own identity or move it after \
+                        restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                        int appId1 = UserHandle.getCallingAppId();
+                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:18: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        android.os.UserHandle.getCallingAppId() will be using your own identity \
+                        instead of the caller's. Either explicitly query your own identity or move \
+                        it after restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                        int appId2 = android.os.UserHandle.getCallingAppId();
+                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:19: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        UserHandle.getCallingUserId() will be using your own identity instead of \
+                        the caller's. Either explicitly query your own identity or move it after \
+                        restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                        int userId1 = UserHandle.getCallingUserId();
+                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        src/test/pkg/TestClass1.java:20: Warning: You cleared the original \
+                        identity with Binder.clearCallingIdentity() and returned into token, so \
+                        android.os.UserHandle.getCallingUserId() will be using your own identity \
+                        instead of the caller's. Either explicitly query your own identity or move \
+                        it after restoring the identity with Binder.restoreCallingIdentity(token). \
+                        [UseOfCallerAwareMethodsWithClearedIdentity]
+                                        int userId2 = android.os.UserHandle.getCallingUserId();
+                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 12 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    /** Stubs for classes used for testing */
+
+    private val binderStub: TestFile = java(
+            """
+            package android.os;
+            public class Binder {
+                public static final native long clearCallingIdentity() {
+                    return 0;
+                }
+                public static final native void restoreCallingIdentity(long token) {
+                }
+                public static final native int getCallingPid() {
+                    return 0;
+                }
+                public static final native int getCallingUid() {
+                    return 0;
+                }
+                public static final int getCallingUidOrThrow() {
+                    return 0;
+                }
+                public static final @NonNull UserHandle getCallingUserHandle() {
+                    return UserHandle.of(UserHandle.getUserId(getCallingUid()));
+                }
+            }
+            """
+    ).indented()
+
+    private val userHandleStub: TestFile = java(
+            """
+            package android.os;
+            import android.annotation.AppIdInt;
+            import android.annotation.UserIdInt;
+            public class UserHandle {
+                public static @AppIdInt int getCallingAppId() {
+                    return getAppId(Binder.getCallingUid());
+                }
+                public static @UserIdInt int getCallingUserId() {
+                    return getUserId(Binder.getCallingUid());
+                }
+                public static @UserIdInt int getUserId(int uid) {
+                    return 0;
+                }
+                public static @AppIdInt int getAppId(int uid) {
+                    return 0;
+                }
+                public static UserHandle of(@UserIdInt int userId) {
+                    return new UserHandle();
+                }
+            }
+            """
+    ).indented()
+
+    private val userIdIntStub: TestFile = java(
+            """
+            package android.annotation;
+            public @interface UserIdInt {
+            }
+            """
+    ).indented()
+
+    private val appIdIntStub: TestFile = java(
+            """
+            package android.annotation;
+            public @interface AppIdInt {
+            }
+            """
+    ).indented()
+
+    private val stubs = arrayOf(binderStub, userHandleStub, userIdIntStub, appIdIntStub)
+
+    // Substitutes "backslash + new line" with an empty string to imitate line continuation
+    private fun String.addLineContinuation(): String = this.trimIndent().replace("\\\n", "")
+}