Merge "Stop differentiating between left and right ALT" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index bfe188d..b782ad1 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -22,6 +22,7 @@
         "aconfig_mediacodec_flags_java_lib",
         "android.adaptiveauth.flags-aconfig-java",
         "android.app.flags-aconfig-java",
+        "android.app.ondeviceintelligence-aconfig-java",
         "android.app.smartspace.flags-aconfig-java",
         "android.app.usage.flags-aconfig-java",
         "android.app.wearable.flags-aconfig-java",
@@ -545,6 +546,19 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+// OnDeviceIntelligence
+aconfig_declarations {
+    name: "android.app.ondeviceintelligence-aconfig",
+    package: "android.app.ondeviceintelligence.flags",
+    srcs: ["core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.app.ondeviceintelligence-aconfig-java",
+    aconfig_declarations: "android.app.ondeviceintelligence-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Permissions
 aconfig_declarations {
     name: "android.permission.flags-aconfig",
@@ -971,6 +985,11 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+cc_aconfig_library {
+    name: "android.tracing.flags_c_lib",
+    aconfig_declarations: "android.tracing.flags-aconfig",
+}
+
 // App Widgets
 aconfig_declarations {
     name: "android.appwidget.flags-aconfig",
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 84145be..2ff8b4e 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/blobstore/Android.bp b/apct-tests/perftests/blobstore/Android.bp
index 2590fe3..e9353fe 100644
--- a/apct-tests/perftests/blobstore/Android.bp
+++ b/apct-tests/perftests/blobstore/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp
index 638403d..5e559d7 100644
--- a/apct-tests/perftests/contentcapture/Android.bp
+++ b/apct-tests/perftests/contentcapture/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index e1b3241..e092499 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_framework_accessibility",
     // 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"
diff --git a/apct-tests/perftests/core/apps/overlay/Android.bp b/apct-tests/perftests/core/apps/overlay/Android.bp
index 6465307..2170fa7 100644
--- a/apct-tests/perftests/core/apps/overlay/Android.bp
+++ b/apct-tests/perftests/core/apps/overlay/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_accessibility",
     // 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"
@@ -25,149 +26,150 @@
     name: "Overlay0",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay0",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay1",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay1",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay2",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay2",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay3",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay3",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay4",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay4",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay5",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay5",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay6",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay6",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay7",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay7",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "Overlay8",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay8",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "Overlay9",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay9",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay0",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large0",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay1",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large1",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay2",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large2",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay3",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large3",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay4",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large4",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay5",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large5",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay6",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large6",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay7",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large7",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay8",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large8",
-    ]
+    ],
 }
 
 android_test_helper_app {
     name: "LargeOverlay9",
-    resource_dirs : [ "res_large" ],
+    resource_dirs: ["res_large"],
     aaptflags: [
         "--rename-manifest-package com.android.perftests.overlay.large9",
-    ]
+    ],
 }
 
 java_library {
diff --git a/apct-tests/perftests/core/apps/reources_manager/Android.bp b/apct-tests/perftests/core/apps/reources_manager/Android.bp
index 766b8c4..96b9d6a 100644
--- a/apct-tests/perftests/core/apps/reources_manager/Android.bp
+++ b/apct-tests/perftests/core/apps/reources_manager/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_accessibility",
     // 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"
diff --git a/apct-tests/perftests/core/jni/Android.bp b/apct-tests/perftests/core/jni/Android.bp
index b92b13b..a9c9526 100644
--- a/apct-tests/perftests/core/jni/Android.bp
+++ b/apct-tests/perftests/core/jni/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_accessibility",
     // 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"
diff --git a/apct-tests/perftests/healthconnect/Android.bp b/apct-tests/perftests/healthconnect/Android.bp
index c2d0a6f..c38a24e 100644
--- a/apct-tests/perftests/healthconnect/Android.bp
+++ b/apct-tests/perftests/healthconnect/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/inputmethod/Android.bp b/apct-tests/perftests/inputmethod/Android.bp
index f2f1f75..7fcfdea 100644
--- a/apct-tests/perftests/inputmethod/Android.bp
+++ b/apct-tests/perftests/inputmethod/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_method_framework",
     // 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"
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 45c6b8c..1653edc 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp b/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp
index 892c140..022655d 100644
--- a/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp
+++ b/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
index b6ea54d..02fc12c 100644
--- a/apct-tests/perftests/packagemanager/Android.bp
+++ b/apct-tests/perftests/packagemanager/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/packagemanager/apps/query-all/Android.bp b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
index b2339d5..6984936 100644
--- a/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
+++ b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
@@ -25,299 +26,348 @@
     name: "QueriesAll0",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration0",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll1",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration1",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll2",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration2",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll3",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration3",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll4",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration4",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll5",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration5",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll6",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration6",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll7",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration7",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll8",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration8",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll9",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration9",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll10",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration10",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll11",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration11",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll12",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration12",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll13",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration13",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll14",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration14",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll15",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration15",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll16",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration16",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll17",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration17",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll18",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration18",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll19",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration19",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll20",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration20",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll21",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration21",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll22",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration22",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll23",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration23",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll24",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration24",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll25",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration25",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll26",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration26",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll27",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration27",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll28",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration28",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll29",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration29",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll30",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration30",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll31",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration31",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll32",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration32",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll33",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration33",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll34",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration34",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll35",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration35",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll36",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration36",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll37",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration37",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll38",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration38",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll39",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration39",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll40",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration40",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll41",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration41",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll42",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration42",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll43",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration43",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll44",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration44",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll45",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration45",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll46",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration46",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll47",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration47",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll48",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration48",
-    ]
+    ],
 }
+
 android_test_helper_app {
     name: "QueriesAll49",
     aaptflags: [
         "--rename-manifest-package com.android.perftests.appenumeration49",
-    ]
+    ],
 }
diff --git a/apct-tests/perftests/permission/Android.bp b/apct-tests/perftests/permission/Android.bp
index b80a6af..bc8e769 100644
--- a/apct-tests/perftests/permission/Android.bp
+++ b/apct-tests/perftests/permission/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp b/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp
index 1ad20b6..d503972 100644
--- a/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp
+++ b/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/rubidium/Android.bp b/apct-tests/perftests/rubidium/Android.bp
index ebd228f..4f4fb11 100644
--- a/apct-tests/perftests/rubidium/Android.bp
+++ b/apct-tests/perftests/rubidium/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/settingsprovider/Android.bp b/apct-tests/perftests/settingsprovider/Android.bp
index 43ec0e0..e4aa14c 100644
--- a/apct-tests/perftests/settingsprovider/Android.bp
+++ b/apct-tests/perftests/settingsprovider/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/surfaceflinger/Android.bp b/apct-tests/perftests/surfaceflinger/Android.bp
index 21d0d44..735c725 100644
--- a/apct-tests/perftests/surfaceflinger/Android.bp
+++ b/apct-tests/perftests/surfaceflinger/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 1011267..cf99771 100644
--- a/apct-tests/perftests/textclassifier/Android.bp
+++ b/apct-tests/perftests/textclassifier/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/utils/Android.bp b/apct-tests/perftests/utils/Android.bp
index 6c46a9b..d2653cd 100644
--- a/apct-tests/perftests/utils/Android.bp
+++ b/apct-tests/perftests/utils/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index 903cf8c..e9357f4 100644
--- a/apct-tests/perftests/windowmanager/Android.bp
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/core/api/current.txt b/core/api/current.txt
index e8a342d..4a2abf6 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2167,11 +2167,6 @@
     field public static final int notification_large_icon_width = 17104901; // 0x1050005
     field public static final int system_app_widget_background_radius = 17104904; // 0x1050008
     field public static final int system_app_widget_inner_radius = 17104905; // 0x1050009
-    field public static final int system_corner_radius_large;
-    field public static final int system_corner_radius_medium;
-    field public static final int system_corner_radius_small;
-    field public static final int system_corner_radius_xlarge;
-    field public static final int system_corner_radius_xsmall;
     field public static final int thumbnail_height = 17104897; // 0x1050001
     field public static final int thumbnail_width = 17104898; // 0x1050002
   }
@@ -10737,7 +10732,6 @@
     field public static final String DROPBOX_SERVICE = "dropbox";
     field public static final String EUICC_SERVICE = "euicc";
     field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
-    field public static final String FINGERPRINT_SERVICE = "fingerprint";
     field public static final String GAME_SERVICE = "game";
     field public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection";
     field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
@@ -13221,7 +13215,7 @@
     field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
     field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
+    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -20367,54 +20361,6 @@
 
 }
 
-package android.hardware.fingerprint {
-
-  @Deprecated public class FingerprintManager {
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
-    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
-    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
-    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
-    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
-    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
-    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
-    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
-    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
-    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
-    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
-    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
-    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
-    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
-    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
-    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
-    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
-    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
-  }
-
-  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
-    ctor @Deprecated public FingerprintManager.AuthenticationCallback();
-    method @Deprecated public void onAuthenticationError(int, CharSequence);
-    method @Deprecated public void onAuthenticationFailed();
-    method @Deprecated public void onAuthenticationHelp(int, CharSequence);
-    method @Deprecated public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
-  }
-
-  @Deprecated public static class FingerprintManager.AuthenticationResult {
-    method @Deprecated public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
-  }
-
-  @Deprecated public static final class FingerprintManager.CryptoObject {
-    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
-    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
-    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
-    method @Deprecated public javax.crypto.Cipher getCipher();
-    method @Deprecated public javax.crypto.Mac getMac();
-    method @Deprecated public java.security.Signature getSignature();
-  }
-
-}
-
 package android.hardware.input {
 
   public final class HostUsiVersion implements android.os.Parcelable {
@@ -43248,6 +43194,7 @@
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}, conditional=true) public String getLine1Number(android.telecom.PhoneAccountHandle);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_OWN_CALLS) public java.util.List<android.telecom.PhoneAccountHandle> getOwnSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
+    method @FlaggedApi("com.android.server.telecom.flags.get_registered_phone_accounts") @NonNull public java.util.List<android.telecom.PhoneAccount> getRegisteredPhoneAccounts();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
     method @Nullable public android.telecom.PhoneAccountHandle getSimCallManagerForSubscription(int);
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 3c7c0d6..c61f163 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -35,6 +35,7 @@
     method @Deprecated @Nullable public String getFeatureId();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(String);
+    field public static final String FINGERPRINT_SERVICE = "fingerprint";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -145,6 +146,54 @@
 
 }
 
+package android.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManager {
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+  }
+
+  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
+    ctor public FingerprintManager.AuthenticationCallback();
+    method public void onAuthenticationError(int, CharSequence);
+    method public void onAuthenticationFailed();
+    method public void onAuthenticationHelp(int, CharSequence);
+    method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
+  }
+
+  @Deprecated public static class FingerprintManager.AuthenticationResult {
+    method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
+  }
+
+  @Deprecated public static final class FingerprintManager.CryptoObject {
+    ctor public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
+    ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
+    ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
+    method public javax.crypto.Cipher getCipher();
+    method public javax.crypto.Mac getMac();
+    method public java.security.Signature getSignature();
+  }
+
+}
+
 package android.media {
 
   public final class AudioFormat implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d8ba84d..627b703 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -69,6 +69,8 @@
     field public static final String BIND_MUSIC_RECOGNITION_SERVICE = "android.permission.BIND_MUSIC_RECOGNITION_SERVICE";
     field public static final String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
     field public static final String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
+    field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String BIND_ON_DEVICE_INTELLIGENCE_SERVICE = "android.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE";
+    field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String BIND_ON_DEVICE_TRUSTED_SERVICE = "android.permission.BIND_ON_DEVICE_TRUSTED_SERVICE";
     field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
     field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final String BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE = "android.permission.BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE";
@@ -386,7 +388,7 @@
     field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY";
     field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
+    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
     field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE";
     field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
     field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE";
@@ -403,6 +405,7 @@
     field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field @FlaggedApi("android.hardware.biometrics.face_background_authentication") public static final String USE_BACKGROUND_FACE_AUTHENTICATION = "android.permission.USE_BACKGROUND_FACE_AUTHENTICATION";
     field public static final String USE_COLORIZED_NOTIFICATIONS = "android.permission.USE_COLORIZED_NOTIFICATIONS";
+    field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String USE_ON_DEVICE_INTELLIGENCE = "android.permission.USE_ON_DEVICE_INTELLIGENCE";
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
     field public static final String UWB_PRIVILEGED = "android.permission.UWB_PRIVILEGED";
     field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
@@ -2190,6 +2193,139 @@
 
 }
 
+package android.app.ondeviceintelligence {
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class Content implements android.os.Parcelable {
+    ctor public Content(@NonNull android.os.Bundle);
+    method public int describeContents();
+    method @NonNull public android.os.Bundle getData();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.ondeviceintelligence.Content> CREATOR;
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public interface DownloadCallback {
+    method public void onDownloadCompleted(@NonNull android.os.PersistableBundle);
+    method public void onDownloadFailed(int, @Nullable String, @NonNull android.os.PersistableBundle);
+    method public default void onDownloadProgress(long);
+    method public default void onDownloadStarted(long);
+    field public static final int DOWNLOAD_FAILURE_STATUS_DOWNLOADING = 3; // 0x3
+    field public static final int DOWNLOAD_FAILURE_STATUS_NETWORK_FAILURE = 2; // 0x2
+    field public static final int DOWNLOAD_FAILURE_STATUS_NOT_ENOUGH_DISK_SPACE = 1; // 0x1
+    field public static final int DOWNLOAD_FAILURE_STATUS_UNAVAILABLE = 4; // 0x4
+    field public static final int DOWNLOAD_FAILURE_STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class Feature implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.os.PersistableBundle getFeatureParams();
+    method public int getId();
+    method @Nullable public String getModelName();
+    method @Nullable public String getName();
+    method public int getType();
+    method public int getVariant();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.ondeviceintelligence.Feature> CREATOR;
+  }
+
+  public static final class Feature.Builder {
+    ctor public Feature.Builder(int, int, int, @NonNull android.os.PersistableBundle);
+    method @NonNull public android.app.ondeviceintelligence.Feature build();
+    method @NonNull public android.app.ondeviceintelligence.Feature.Builder setFeatureParams(@NonNull android.os.PersistableBundle);
+    method @NonNull public android.app.ondeviceintelligence.Feature.Builder setId(int);
+    method @NonNull public android.app.ondeviceintelligence.Feature.Builder setModelName(@NonNull String);
+    method @NonNull public android.app.ondeviceintelligence.Feature.Builder setName(@NonNull String);
+    method @NonNull public android.app.ondeviceintelligence.Feature.Builder setType(int);
+    method @NonNull public android.app.ondeviceintelligence.Feature.Builder setVariant(int);
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class FeatureDetails implements android.os.Parcelable {
+    ctor public FeatureDetails(@android.app.ondeviceintelligence.FeatureDetails.Status int, @NonNull android.os.PersistableBundle);
+    ctor public FeatureDetails(@android.app.ondeviceintelligence.FeatureDetails.Status int);
+    method public int describeContents();
+    method @NonNull public android.os.PersistableBundle getFeatureDetailParams();
+    method @android.app.ondeviceintelligence.FeatureDetails.Status public int getStatus();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.ondeviceintelligence.FeatureDetails> CREATOR;
+    field public static final int FEATURE_STATUS_AVAILABLE = 3; // 0x3
+    field public static final int FEATURE_STATUS_DOWNLOADABLE = 1; // 0x1
+    field public static final int FEATURE_STATUS_DOWNLOADING = 2; // 0x2
+    field public static final int FEATURE_STATUS_SERVICE_UNAVAILABLE = 4; // 0x4
+    field public static final int FEATURE_STATUS_UNAVAILABLE = 0; // 0x0
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_USE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.FIELD}) public static @interface FeatureDetails.Status {
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class FilePart implements android.os.Parcelable {
+    ctor public FilePart(@NonNull String, @NonNull android.os.PersistableBundle, @NonNull String) throws java.io.FileNotFoundException;
+    ctor public FilePart(@NonNull String, @NonNull android.os.PersistableBundle, @NonNull java.io.FileInputStream) throws java.io.IOException;
+    method public int describeContents();
+    method @NonNull public java.io.FileInputStream getFileInputStream();
+    method @NonNull public String getFilePartKey();
+    method @NonNull public android.os.PersistableBundle getFilePartParams();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.ondeviceintelligence.FilePart> CREATOR;
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public class OnDeviceIntelligenceManager {
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getFeature(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.Feature,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getFeatureDetails(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.FeatureDetails,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void getVersion(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.LongConsumer);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void listFeatures(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.util.List<android.app.ondeviceintelligence.Feature>,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void processRequest(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void processRequestStreaming(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull java.util.concurrent.Executor, @NonNull android.app.ondeviceintelligence.StreamingResponseReceiver<android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void requestFeatureDownload(@NonNull android.app.ondeviceintelligence.Feature, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.app.ondeviceintelligence.DownloadCallback);
+    method @RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void requestTokenCount(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Long,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    field public static final String API_VERSION_BUNDLE_KEY = "ApiVersionBundleKey";
+    field public static final int REQUEST_TYPE_EMBEDDINGS = 2; // 0x2
+    field public static final int REQUEST_TYPE_INFERENCE = 0; // 0x0
+    field public static final int REQUEST_TYPE_PREPARE = 1; // 0x1
+  }
+
+  public static class OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException extends java.lang.Exception {
+    ctor public OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException(int, @NonNull String, @NonNull android.os.PersistableBundle);
+    ctor public OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException(int, @NonNull android.os.PersistableBundle);
+    method public int getErrorCode();
+    method @NonNull public android.os.PersistableBundle getErrorParams();
+    field public static final int ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE = 1000; // 0x3e8
+  }
+
+  public static class OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException extends android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException {
+    ctor public OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException(int, @NonNull String, @NonNull android.os.PersistableBundle);
+    ctor public OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException(int, @NonNull android.os.PersistableBundle);
+    field public static final int PROCESSING_ERROR_BAD_DATA = 2; // 0x2
+    field public static final int PROCESSING_ERROR_BAD_REQUEST = 3; // 0x3
+    field public static final int PROCESSING_ERROR_BUSY = 9; // 0x9
+    field public static final int PROCESSING_ERROR_CANCELLED = 7; // 0x7
+    field public static final int PROCESSING_ERROR_COMPUTE_ERROR = 5; // 0x5
+    field public static final int PROCESSING_ERROR_INTERNAL = 14; // 0xe
+    field public static final int PROCESSING_ERROR_IPC_ERROR = 6; // 0x6
+    field public static final int PROCESSING_ERROR_NOT_AVAILABLE = 8; // 0x8
+    field public static final int PROCESSING_ERROR_REQUEST_NOT_SAFE = 4; // 0x4
+    field public static final int PROCESSING_ERROR_REQUEST_TOO_LARGE = 12; // 0xc
+    field public static final int PROCESSING_ERROR_RESPONSE_NOT_SAFE = 11; // 0xb
+    field public static final int PROCESSING_ERROR_SAFETY_ERROR = 10; // 0xa
+    field public static final int PROCESSING_ERROR_SERVICE_UNAVAILABLE = 15; // 0xf
+    field public static final int PROCESSING_ERROR_SUSPENDED = 13; // 0xd
+    field public static final int PROCESSING_ERROR_UNKNOWN = 1; // 0x1
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public final class ProcessingSignal {
+    ctor public ProcessingSignal();
+    method public void sendSignal(@NonNull android.os.PersistableBundle);
+    method public void setOnProcessingSignalCallback(@NonNull java.util.concurrent.Executor, @Nullable android.app.ondeviceintelligence.ProcessingSignal.OnProcessingSignalCallback);
+  }
+
+  public static interface ProcessingSignal.OnProcessingSignalCallback {
+    method public void onSignalReceived(@NonNull android.os.PersistableBundle);
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public interface StreamingResponseReceiver<R, T, E extends java.lang.Throwable> extends android.os.OutcomeReceiver<R,E> {
+    method public void onNewContent(@NonNull T);
+  }
+
+}
+
 package android.app.people {
 
   public final class PeopleManager {
@@ -3637,6 +3773,7 @@
     field public static final String NETD_SERVICE = "netd";
     field @Deprecated public static final String NETWORK_SCORE_SERVICE = "network_score";
     field public static final String OEM_LOCK_SERVICE = "oem_lock";
+    field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String ON_DEVICE_INTELLIGENCE_SERVICE = "on_device_intelligence";
     field public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
     field public static final String PERMISSION_SERVICE = "permission";
     field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
@@ -3651,7 +3788,7 @@
     field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final String TETHERING_SERVICE = "tethering";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled") public static final String THREAD_NETWORK_SERVICE = "thread_network";
+    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
     field public static final String TIME_MANAGER_SERVICE = "time_manager";
     field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
@@ -12821,6 +12958,34 @@
 
 }
 
+package android.service.ondeviceintelligence {
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public abstract class OnDeviceIntelligenceService extends android.app.Service {
+    ctor public OnDeviceIntelligenceService();
+    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public abstract void onDownloadFeature(@NonNull android.app.ondeviceintelligence.Feature, @Nullable android.os.CancellationSignal, @NonNull android.app.ondeviceintelligence.DownloadCallback);
+    method public abstract void onGetFeature(int, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.Feature,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    method public abstract void onGetFeatureDetails(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.FeatureDetails,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    method public abstract void onGetReadOnlyFeatureFileDescriptorMap(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,android.os.ParcelFileDescriptor>>);
+    method public abstract void onGetVersion(@NonNull java.util.function.LongConsumer);
+    method public abstract void onListFeatures(@NonNull android.os.OutcomeReceiver<java.util.List<android.app.ondeviceintelligence.Feature>,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    field public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceIntelligenceService";
+  }
+
+  @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public abstract class OnDeviceTrustedInferenceService extends android.app.Service {
+    ctor public OnDeviceTrustedInferenceService();
+    method public final void fetchFeatureFileInputStreamMap(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.io.FileInputStream>>);
+    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method @NonNull public abstract void onCountTokens(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, @Nullable android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<java.lang.Long,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
+    method @NonNull public abstract void onProcessRequest(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
+    method @NonNull public abstract void onProcessRequestStreaming(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull android.app.ondeviceintelligence.StreamingResponseReceiver<android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
+    method public final java.io.FileInputStream openFileInput(@NonNull String) throws java.io.FileNotFoundException;
+    method public final void openFileInputAsync(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.io.FileInputStream>) throws java.io.FileNotFoundException;
+    field public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceTrustedInferenceService";
+  }
+
+}
+
 package android.service.persistentdata {
 
   @FlaggedApi("android.security.frp_enforcement") public class PersistentDataBlockManager {
@@ -13453,6 +13618,7 @@
 
   @FlaggedApi("android.service.voice.flags.allow_complex_results_egress_from_vqds") public final class VisualQueryDetectedResult implements android.os.Parcelable {
     method public int describeContents();
+    method @Nullable public byte[] getAccessibilityDetectionData();
     method public static int getMaxSpeakerId();
     method @NonNull public String getPartialQuery();
     method public int getSpeakerId();
@@ -13463,6 +13629,7 @@
   public static final class VisualQueryDetectedResult.Builder {
     ctor public VisualQueryDetectedResult.Builder();
     method @NonNull public android.service.voice.VisualQueryDetectedResult build();
+    method @NonNull public android.service.voice.VisualQueryDetectedResult.Builder setAccessibilityDetectionData(@NonNull byte...);
     method @NonNull public android.service.voice.VisualQueryDetectedResult.Builder setPartialQuery(@NonNull String);
     method @NonNull public android.service.voice.VisualQueryDetectedResult.Builder setSpeakerId(int);
   }
@@ -13500,7 +13667,10 @@
   }
 
   public class VisualQueryDetector {
+    method @FlaggedApi("android.service.voice.flags.allow_complex_results_egress_from_vqds") public void clearAccessibilityDetectionEnabledListener();
     method public void destroy();
+    method @FlaggedApi("android.service.voice.flags.allow_complex_results_egress_from_vqds") public boolean isAccessibilityDetectionEnabled();
+    method @FlaggedApi("android.service.voice.flags.allow_complex_results_egress_from_vqds") public void setAccessibilityDetectionEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(allOf={android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}) public boolean startRecognition();
     method @RequiresPermission(allOf={android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}) public boolean stopRecognition();
     method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory);
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index ca9fab8..1923641 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -509,6 +509,12 @@
     Methods must not throw generic exceptions (`java.lang.Throwable`)
 
 
+InvalidNullabilityOverride: android.service.ondeviceintelligence.OnDeviceIntelligenceService#onBind(android.content.Intent) parameter #0:
+    Invalid nullability on parameter `intent` in method `onBind`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
+InvalidNullabilityOverride: android.service.ondeviceintelligence.OnDeviceTrustedInferenceService#onBind(android.content.Intent) parameter #0:
+    Invalid nullability on parameter `intent` in method `onBind`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
+InvalidNullabilityOverride: android.service.ondeviceintelligence.OnDeviceTrustedInferenceService#openFileInput(String) parameter #0:
+    Invalid nullability on parameter `filename` in method `openFileInput`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
 InvalidNullabilityOverride: android.service.textclassifier.TextClassifierService#onUnbind(android.content.Intent) parameter #0:
     Invalid nullability on parameter `intent` in method `onUnbind`. Parameters of overrides cannot be NonNull if the super parameter is unannotated.
 InvalidNullabilityOverride: android.service.voice.HotwordDetectionService#getSystemService(String) parameter #0:
@@ -565,6 +571,8 @@
     Missing nullability on parameter `args` in method `dump`
 MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
     Missing nullability on parameter `base` in method `attachBaseContext`
+MissingNullability: android.service.ondeviceintelligence.OnDeviceTrustedInferenceService#openFileInput(String):
+    Missing nullability on method `openFileInput` return
 MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
     Missing nullability on parameter `intent` in method `onUnbind`
 MissingNullability: android.telephony.data.DataService#onUnbind(android.content.Intent) parameter #0:
@@ -1877,6 +1885,8 @@
     Documentation mentions 'TODO'
 Todo: android.app.NotificationManager#isNotificationAssistantAccessGranted(android.content.ComponentName):
     Documentation mentions 'TODO'
+Todo: android.app.ondeviceintelligence.OnDeviceIntelligenceManager#requestFeatureDownload(android.app.ondeviceintelligence.Feature, android.app.ondeviceintelligence.CancellationSignal, java.util.concurrent.Executor, android.app.ondeviceintelligence.DownloadCallback):
+    Documentation mentions 'TODO'
 Todo: android.hardware.camera2.params.StreamConfigurationMap:
     Documentation mentions 'TODO'
 Todo: android.hardware.location.ContextHubManager#getNanoAppInstanceInfo(int):
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 334d9e6..48dcbe5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1548,6 +1548,7 @@
 
   public static class BiometricPrompt.Builder {
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowBackgroundAuthentication(boolean);
+    method @FlaggedApi("android.multiuser.enable_biometrics_to_unlock_private_space") @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowBackgroundAuthentication(boolean, boolean);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowedSensorIds(@NonNull java.util.List<java.lang.Integer>);
   }
 
@@ -1702,15 +1703,7 @@
     field public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; // 0x1
     field public static final int VIRTUAL_DISPLAY_FLAG_OWN_FOCUS = 16384; // 0x4000
     field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
-  }
-
-}
-
-package android.hardware.fingerprint {
-
-  @Deprecated public class FingerprintManager {
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
+    field public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 64; // 0x40
   }
 
 }
@@ -1759,6 +1752,10 @@
     field public static final int DEFAULT_POINTER_SPEED = 0; // 0x0
   }
 
+  public class VirtualKeyboard implements java.io.Closeable {
+    method public int getInputDeviceId();
+  }
+
 }
 
 package android.hardware.lights {
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index c1181f5..27808cb 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1931,6 +1931,8 @@
     Documentation mentions 'TODO'
 Todo: android.app.NotificationManager#isNotificationAssistantAccessGranted(android.content.ComponentName):
     Documentation mentions 'TODO'
+Todo: android.app.ondeviceintelligence.OnDeviceIntelligenceManager#requestFeatureDownload(android.app.ondeviceintelligence.Feature, android.app.ondeviceintelligence.CancellationSignal, java.util.concurrent.Executor, android.app.ondeviceintelligence.DownloadCallback):
+    Documentation mentions 'TODO'
 Todo: android.hardware.camera2.params.StreamConfigurationMap:
     Documentation mentions 'TODO'
 Todo: android.hardware.location.ContextHubManager#getNanoAppInstanceInfo(int):
diff --git a/core/api/test-removed.txt b/core/api/test-removed.txt
index d802177..2e44176 100644
--- a/core/api/test-removed.txt
+++ b/core/api/test-removed.txt
@@ -1 +1,10 @@
 // Signature format: 2.0
+package android.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
+  }
+
+}
+
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index f7d7522..42c3272 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -69,6 +69,7 @@
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.inputmethod.EditorInfo;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.CancellationGroup;
 import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
 import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
@@ -1388,7 +1389,9 @@
         getFingerprintGestureController().onGesture(gesture);
     }
 
-    int getConnectionId() {
+    /** @hide */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public int getConnectionId() {
         return mConnectionId;
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 237d31c..f358522 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -5967,14 +5967,19 @@
     }
 
     /**
-     * Used by {@link com.android.systemui.theme.ThemeOverlayController} to notify of color
-     * palette readiness.
+     * Used by ThemeOverlayController to notify when color
+     * palette is ready.
+     *
+     * @param userId The ID of the user where ThemeOverlayController is ready.
+     *
+     * @throws RemoteException
+     *
      * @hide
      */
     @RequiresPermission(Manifest.permission.SET_THEME_OVERLAY_CONTROLLER_READY)
-    public void setThemeOverlayReady(boolean readiness) {
+    public void setThemeOverlayReady(@UserIdInt int userId) {
         try {
-            getService().setThemeOverlayReady(readiness);
+            getService().setThemeOverlayReady(userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0ae2e01..062b89e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1264,5 +1264,5 @@
      * palette readiness.
      * @hide
      */
-    public abstract boolean getThemeOverlayReadiness();
+    public abstract boolean isThemeOverlayReady(int userId);
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 926e297..e6a2c07 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -237,7 +237,6 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.org.conscrypt.TrustedCertificateStore;
 import com.android.server.am.MemInfoDumpProto;
-import com.android.window.flags.Flags;
 
 import dalvik.annotation.optimization.NeverCompile;
 import dalvik.system.AppSpecializationHooks;
@@ -3762,11 +3761,7 @@
         final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread);
         final ActivityResultItem activityResultItem = ActivityResultItem.obtain(
                 activityToken, list);
-        if (Flags.bundleClientTransactionFlag()) {
-            clientTransaction.addTransactionItem(activityResultItem);
-        } else {
-            clientTransaction.addCallback(activityResultItem);
-        }
+        clientTransaction.addTransactionItem(activityResultItem);
         try {
             mAppThread.scheduleTransaction(clientTransaction);
         } catch (RemoteException e) {
@@ -4553,11 +4548,7 @@
         final PauseActivityItem pauseActivityItem = PauseActivityItem.obtain(r.token,
                 r.activity.isFinishing(), /* userLeaving */ true, r.activity.mConfigChangeFlags,
                 /* dontReport */ false, /* autoEnteringPip */ false);
-        if (Flags.bundleClientTransactionFlag()) {
-            transaction.addTransactionItem(pauseActivityItem);
-        } else {
-            transaction.setLifecycleStateRequest(pauseActivityItem);
-        }
+        transaction.addTransactionItem(pauseActivityItem);
         executeTransaction(transaction);
     }
 
@@ -4565,11 +4556,7 @@
         final ClientTransaction transaction = ClientTransaction.obtain(mAppThread);
         final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(r.token,
                 /* isForward */ false, /* shouldSendCompatFakeFocus */ false);
-        if (Flags.bundleClientTransactionFlag()) {
-            transaction.addTransactionItem(resumeActivityItem);
-        } else {
-            transaction.setLifecycleStateRequest(resumeActivityItem);
-        }
+        transaction.addTransactionItem(resumeActivityItem);
         executeTransaction(transaction);
     }
 
@@ -6189,13 +6176,8 @@
                 TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
         // Schedule the transaction.
         final ClientTransaction transaction = ClientTransaction.obtain(mAppThread);
-        if (Flags.bundleClientTransactionFlag()) {
-            transaction.addTransactionItem(activityRelaunchItem);
-            transaction.addTransactionItem(lifecycleRequest);
-        } else {
-            transaction.addCallback(activityRelaunchItem);
-            transaction.setLifecycleStateRequest(lifecycleRequest);
-        }
+        transaction.addTransactionItem(activityRelaunchItem);
+        transaction.addTransactionItem(lifecycleRequest);
         executeTransaction(transaction);
     }
 
diff --git a/core/java/android/app/ComponentCaller.java b/core/java/android/app/ComponentCaller.java
index 14bc003..7e6a9ac 100644
--- a/core/java/android/app/ComponentCaller.java
+++ b/core/java/android/app/ComponentCaller.java
@@ -137,16 +137,18 @@
      *     <li>This is not a real time check, i.e. the permissions have been computed at launch
      *     time.
      *     <li>This method will return the correct result for content URIs passed at launch time,
-     *     specifically the ones from {@link Intent#getData()}, and {@link Intent#getClipData()} in
-     *     the intent of {@code startActivity(intent)}. For others, it will throw an
-     *     {@link IllegalArgumentException}.
+     *     specifically the ones from {@link Intent#getData()}, {@link Intent#EXTRA_STREAM}, and
+     *     {@link Intent#getClipData()} in the intent of {@code startActivity(intent)}. For others,
+     *     it will throw an {@link IllegalArgumentException}.
      * </ul>
      *
      * @param uri The content uri that is being checked
      * @param modeFlags The access modes to check
      * @return {@link PackageManager#PERMISSION_GRANTED} if this activity caller is allowed to
      *         access that uri, or {@link PackageManager#PERMISSION_DENIED} if it is not
-     * @throws IllegalArgumentException if uri is a non-content URI or it wasn't passed at launch
+     * @throws IllegalArgumentException if uri is a non-content URI or it wasn't passed at launch in
+     *                                  {@link Intent#getData()}, {@link Intent#EXTRA_STREAM}, and
+     *                                  {@link Intent#getClipData()}
      * @throws SecurityException if you don't have access to uri
      *
      * @see android.content.Context#checkContentUriPermissionFull(Uri, int, int, int)
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index cc0aafd..7a95720 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -554,11 +554,14 @@
     void bootAnimationComplete();
 
     /**
-     * Used by {@link com.android.systemui.theme.ThemeOverlayController} to notify of color
-     * palette readiness.
+     * Used by {@link com.android.systemui.theme.ThemeOverlayController} to notify when color
+     * palette is ready.
+     *
+     * @param userId The ID of the user where ThemeOverlayController is ready.
+     *
      * @throws RemoteException
      */
-    void setThemeOverlayReady(boolean readiness);
+    void setThemeOverlayReady(int userId);
 
     @UnsupportedAppUsage
     void registerTaskStackListener(in ITaskStackListener listener);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d6e8ae3..26f85f7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -80,6 +80,7 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -3023,37 +3024,44 @@
      * @hide
      */
     public String loadHeaderAppName(Context context) {
-        CharSequence name = null;
-        // Check if there is a non-empty substitute app name and return that.
-        if (extras.containsKey(EXTRA_SUBSTITUTE_APP_NAME)) {
-            name = extras.getString(EXTRA_SUBSTITUTE_APP_NAME);
-            if (!TextUtils.isEmpty(name)) {
-                return name.toString();
-            }
-        }
-        // If not, try getting the app info from extras.
-        if (context == null) {
-            return null;
-        }
-        final PackageManager pm = context.getPackageManager();
-        if (TextUtils.isEmpty(name)) {
-            if (extras.containsKey(EXTRA_BUILDER_APPLICATION_INFO)) {
-                final ApplicationInfo info = extras.getParcelable(EXTRA_BUILDER_APPLICATION_INFO,
-                        ApplicationInfo.class);
-                if (info != null) {
-                    name = pm.getApplicationLabel(info);
+        Trace.beginSection("Notification#loadHeaderAppName");
+
+        try {
+            CharSequence name = null;
+            // Check if there is a non-empty substitute app name and return that.
+            if (extras.containsKey(EXTRA_SUBSTITUTE_APP_NAME)) {
+                name = extras.getString(EXTRA_SUBSTITUTE_APP_NAME);
+                if (!TextUtils.isEmpty(name)) {
+                    return name.toString();
                 }
             }
+            // If not, try getting the app info from extras.
+            if (context == null) {
+                return null;
+            }
+            final PackageManager pm = context.getPackageManager();
+            if (TextUtils.isEmpty(name)) {
+                if (extras.containsKey(EXTRA_BUILDER_APPLICATION_INFO)) {
+                    final ApplicationInfo info = extras.getParcelable(
+                            EXTRA_BUILDER_APPLICATION_INFO,
+                            ApplicationInfo.class);
+                    if (info != null) {
+                        name = pm.getApplicationLabel(info);
+                    }
+                }
+            }
+            // If that's still empty, use the one from the context directly.
+            if (TextUtils.isEmpty(name)) {
+                name = pm.getApplicationLabel(context.getApplicationInfo());
+            }
+            // If there's still nothing, ¯\_(ツ)_/¯
+            if (TextUtils.isEmpty(name)) {
+                return null;
+            }
+            return name.toString();
+        } finally {
+            Trace.endSection();
         }
-        // If that's still empty, use the one from the context directly.
-        if (TextUtils.isEmpty(name)) {
-            name = pm.getApplicationLabel(context.getApplicationInfo());
-        }
-        // If there's still nothing, ¯\_(ツ)_/¯
-        if (TextUtils.isEmpty(name)) {
-            return null;
-        }
-        return name.toString();
     }
 
     /**
@@ -6722,23 +6730,29 @@
          */
         @NonNull
         public static Notification.Builder recoverBuilder(Context context, Notification n) {
-            // Re-create notification context so we can access app resources.
-            ApplicationInfo applicationInfo = n.extras.getParcelable(
-                    EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
-            Context builderContext;
-            if (applicationInfo != null) {
-                try {
-                    builderContext = context.createApplicationContext(applicationInfo,
-                            Context.CONTEXT_RESTRICTED);
-                } catch (NameNotFoundException e) {
-                    Log.e(TAG, "ApplicationInfo " + applicationInfo + " not found");
-                    builderContext = context;  // try with our context
-                }
-            } else {
-                builderContext = context; // try with given context
-            }
+            Trace.beginSection("Notification.Builder#recoverBuilder");
 
-            return new Builder(builderContext, n);
+            try {
+                // Re-create notification context so we can access app resources.
+                ApplicationInfo applicationInfo = n.extras.getParcelable(
+                        EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
+                Context builderContext;
+                if (applicationInfo != null) {
+                    try {
+                        builderContext = context.createApplicationContext(applicationInfo,
+                                Context.CONTEXT_RESTRICTED);
+                    } catch (NameNotFoundException e) {
+                        Log.e(TAG, "ApplicationInfo " + applicationInfo + " not found");
+                        builderContext = context;  // try with our context
+                    }
+                } else {
+                    builderContext = context; // try with given context
+                }
+
+                return new Builder(builderContext, n);
+            } finally {
+                Trace.endSection();
+            }
         }
 
         /**
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 24a5157..6255260 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -550,7 +550,7 @@
     @UnsupportedAppUsage
     protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
             @Nullable ApkAssetsSupplier apkSupplier) {
-        final AssetManager.Builder builder = new AssetManager.Builder();
+        final AssetManager.Builder builder = new AssetManager.Builder().setNoInit();
 
         final ArrayList<ApkKey> apkKeys = extractApkKeys(key);
         for (int i = 0, n = apkKeys.size(); i < n; i++) {
@@ -1555,7 +1555,7 @@
         } else if(overlayPaths == null) {
             return ArrayUtils.cloneOrNull(resourceDirs);
         } else {
-            final ArrayList<String> paths = new ArrayList<>();
+            final var paths = new ArrayList<String>(overlayPaths.length + resourceDirs.length);
             for (final String path : overlayPaths) {
                 paths.add(path);
             }
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index a045eae..7903f1c 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import static android.app.Flags.enableNightModeCache;
+import static android.app.Flags.enableNightModeBinderCache;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
@@ -916,7 +916,7 @@
      *
      * @hide
      */
-    @FlaggedApi(Flags.FLAG_ENABLE_NIGHT_MODE_CACHE)
+    @FlaggedApi(Flags.FLAG_ENABLE_NIGHT_MODE_BINDER_CACHE)
     public static void invalidateNightModeCache() {
         IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM,
                 NIGHT_MODE_API);
@@ -938,7 +938,7 @@
      * @see #setNightMode(int)
      */
     public @NightMode int getNightMode() {
-        if (enableNightModeCache()) {
+        if (enableNightModeBinderCache()) {
             return mNightModeCache.query(null);
         } else {
             return getNightModeFromServer();
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 7d5d5c1..986205a 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -16,10 +16,11 @@
 
 package android.app.admin;
 
+import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED;
+
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.app.admin.flags.Flags;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -185,7 +186,7 @@
      * <p>This mode only allows a single secondary user on the device blocking the creation of
      * additional secondary users.
      */
-    @FlaggedApi(Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED)
+    @FlaggedApi(FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED)
     public static final int HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER = 2;
 
     @IntDef({HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED, HEADLESS_DEVICE_OWNER_MODE_AFFILIATED,
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
index 3c56aaf..eeaf0b3 100644
--- a/core/java/android/app/admin/DevicePolicyIdentifiers.java
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -16,13 +16,13 @@
 
 package android.app.admin;
 
+import static android.app.admin.flags.Flags.FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED;
 import static android.app.admin.flags.Flags.FLAG_SECURITY_LOG_V2_ENABLED;
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.app.admin.flags.Flags;
 import android.os.UserManager;
 
 import java.util.Objects;
@@ -188,13 +188,13 @@
     /**
      * String identifier for {@link DevicePolicyManager#setUsbDataSignalingEnabled}.
      */
-    @FlaggedApi(Flags.FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
+    @FlaggedApi(FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
     public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
 
     /**
      * String identifier for {@link DevicePolicyManager#setRequiredPasswordComplexity}.
      */
-    @FlaggedApi(Flags.FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
+    @FlaggedApi(FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
     public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a6fda9d..083705b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -53,8 +53,11 @@
 import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
 import static android.Manifest.permission.SET_TIME;
 import static android.Manifest.permission.SET_TIME_ZONE;
+import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
 import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
 import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
+import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED;
+import static android.app.admin.flags.Flags.FLAG_PERMISSION_MIGRATION_FOR_ZERO_TRUST_API_ENABLED;
 import static android.app.admin.flags.Flags.FLAG_SECURITY_LOG_V2_ENABLED;
 import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
 import static android.app.admin.flags.Flags.FLAG_IS_MTE_POLICY_ENFORCED;
@@ -90,7 +93,6 @@
 import android.app.IServiceConnection;
 import android.app.KeyguardManager;
 import android.app.admin.SecurityLog.SecurityEvent;
-import android.app.admin.flags.Flags;
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
@@ -153,10 +155,10 @@
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.org.conscrypt.TrustedCertificateStore;
-import com.android.internal.os.Zygote;
 
 import java.io.ByteArrayInputStream;
 import java.io.FileNotFoundException;
@@ -2879,7 +2881,7 @@
      * @hide
      */
     @SystemApi
-    @FlaggedApi(Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED)
+    @FlaggedApi(FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED)
     public static final int STATUS_HEADLESS_ONLY_SYSTEM_USER = 17;
 
     /**
@@ -13447,7 +13449,7 @@
      */
     @RequiresPermission(value = MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES, conditional = true)
     @SuppressLint("RequiresPermission")
-    @FlaggedApi(Flags.FLAG_PERMISSION_MIGRATION_FOR_ZERO_TRUST_API_ENABLED)
+    @FlaggedApi(FLAG_PERMISSION_MIGRATION_FOR_ZERO_TRUST_API_ENABLED)
     public @Nullable SystemUpdateInfo getPendingSystemUpdate(@Nullable ComponentName admin) {
         throwIfParentInstance("getPendingSystemUpdate");
         try {
@@ -16608,7 +16610,7 @@
      */
     @RequiresPermission(value = MANAGE_DEVICE_POLICY_CERTIFICATES, conditional = true)
     @SuppressLint("RequiresPermission")
-    @FlaggedApi(Flags.FLAG_PERMISSION_MIGRATION_FOR_ZERO_TRUST_API_ENABLED)
+    @FlaggedApi(FLAG_PERMISSION_MIGRATION_FOR_ZERO_TRUST_API_ENABLED)
     @NonNull public String getEnrollmentSpecificId() {
         throwIfParentInstance("getEnrollmentSpecificId");
         if (mService == null) {
@@ -17134,7 +17136,7 @@
      */
     @SystemApi
     @RequiresPermission(value = MANAGE_DEVICE_POLICY_THEFT_DETECTION)
-    @FlaggedApi(Flags.FLAG_DEVICE_THEFT_API_ENABLED)
+    @FlaggedApi(FLAG_DEVICE_THEFT_API_ENABLED)
     public boolean isTheftDetectionTriggered() {
         throwIfParentInstance("isTheftDetectionTriggered");
         if (mService == null) {
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index ed1b8ca..477f2e0 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -16,6 +16,8 @@
 
 package android.app.admin;
 
+import static android.app.admin.flags.Flags.FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED;
+
 import android.Manifest;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -24,7 +26,6 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.app.admin.flags.Flags;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.os.Build;
@@ -610,7 +611,7 @@
      * <li> [2] backup service state ({@code Integer}, 1 for enabled, 0 for disabled)
      * @see DevicePolicyManager#setBackupServiceEnabled(ComponentName, boolean)
      */
-    @FlaggedApi(Flags.FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED)
+    @FlaggedApi(FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED)
     public static final int TAG_BACKUP_SERVICE_TOGGLED =
             SecurityLogTags.SECURITY_BACKUP_SERVICE_TOGGLED;
     /**
diff --git a/core/java/android/app/ondeviceintelligence/Content.aidl b/core/java/android/app/ondeviceintelligence/Content.aidl
new file mode 100644
index 0000000..40f0ef9
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/Content.aidl
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+/**
+  * @hide
+  */
+parcelable Content;
diff --git a/core/java/android/app/ondeviceintelligence/Content.java b/core/java/android/app/ondeviceintelligence/Content.java
new file mode 100644
index 0000000..51bd156
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/Content.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Represents content sent to and received from the on-device inference service.
+ * Can contain a collection of text, image, and binary parts or any combination of these.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public final class Content implements Parcelable {
+    //TODO: Improve javadoc after adding validation logic.
+    private static final String TAG = "Content";
+    private final Bundle mData;
+
+    /**
+     * Create a content object using a Bundle of only known types that are read-only.
+     */
+    public Content(@NonNull Bundle data) {
+        Objects.requireNonNull(data);
+        validateBundleData(data);
+        this.mData = data;
+    }
+
+    /**
+     * Returns the Content's data represented as a Bundle.
+     */
+    @NonNull
+    public Bundle getData() {
+        return mData;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBundle(mData);
+    }
+
+    @Override
+    public int describeContents() {
+        int mask = 0;
+        mask |= mData.describeContents();
+        return mask;
+    }
+
+    @NonNull
+    public static final Creator<Content> CREATOR = new Creator<>() {
+        @Override
+        @NonNull
+        public Content createFromParcel(@NonNull Parcel in) {
+            return new Content(in.readBundle(getClass().getClassLoader()));
+        }
+
+        @Override
+        @NonNull
+        public Content[] newArray(int size) {
+            return new Content[size];
+        }
+    };
+
+    private void validateBundleData(Bundle unused) {
+        // TODO: Validate there are only known types.
+    }
+}
diff --git a/core/java/android/app/ondeviceintelligence/DownloadCallback.java b/core/java/android/app/ondeviceintelligence/DownloadCallback.java
new file mode 100644
index 0000000..684c71f
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/DownloadCallback.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.PersistableBundle;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Callback functions used for feature downloading via the
+ * {@link OnDeviceIntelligenceManager#requestFeatureDownload}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public interface DownloadCallback {
+    int DOWNLOAD_FAILURE_STATUS_UNKNOWN = 0;
+
+    /**
+     * Sent when feature download could not succeed due to there being no available disk space on
+     * the device.
+     */
+    int DOWNLOAD_FAILURE_STATUS_NOT_ENOUGH_DISK_SPACE = 1;
+
+    /**
+     * Sent when feature download could not succeed due to a network error.
+     */
+    int DOWNLOAD_FAILURE_STATUS_NETWORK_FAILURE = 2;
+
+    /**
+     * Sent when feature download has been initiated already, hence no need to request download
+     * again. Caller can query {@link OnDeviceIntelligenceManager#getFeatureStatus} to check if
+     * download has been completed.
+     */
+    int DOWNLOAD_FAILURE_STATUS_DOWNLOADING = 3;
+
+    /**
+     * Sent when feature download did not start due to errors (e.g. remote exception of features not
+     * available). Caller can query {@link OnDeviceIntelligenceManager#getFeatureStatus} to check
+     * if feature-status is {@link FeatureDetails#FEATURE_STATUS_DOWNLOADABLE}.
+     */
+    int DOWNLOAD_FAILURE_STATUS_UNAVAILABLE = 4;
+
+    /** @hide */
+    @IntDef(value = {
+            DOWNLOAD_FAILURE_STATUS_UNKNOWN,
+            DOWNLOAD_FAILURE_STATUS_NOT_ENOUGH_DISK_SPACE,
+            DOWNLOAD_FAILURE_STATUS_NETWORK_FAILURE,
+            DOWNLOAD_FAILURE_STATUS_DOWNLOADING,
+            DOWNLOAD_FAILURE_STATUS_UNAVAILABLE
+    }, open = true)
+    @Retention(RetentionPolicy.SOURCE)
+    @interface DownloadFailureStatus {
+    }
+
+    /**
+     * Called when model download started properly.
+     *
+     * @param bytesToDownload the total bytes to be downloaded for this {@link Feature}
+     */
+    default void onDownloadStarted(long bytesToDownload) {
+    }
+
+    /**
+     * Called when model download failed.
+     *
+     * @param failureStatus the download failure status
+     * @param errorMessage  the error message associated with the download failure
+     */
+    void onDownloadFailed(
+            @DownloadFailureStatus int failureStatus,
+            @Nullable String errorMessage,
+            @NonNull PersistableBundle errorParams);
+
+    /**
+     * Called when model download is in progress.
+     *
+     * @param totalBytesDownloaded the already downloaded bytes for this {@link Feature}
+     */
+    default void onDownloadProgress(long totalBytesDownloaded) {
+    }
+
+    /**
+     * Called when model download via MDD completed. The remote implementation can populate any
+     * associated download params like file stats etc. in this callback to inform the client.
+     *
+     * @param downloadParams params containing info about the completed download.
+     */
+    void onDownloadCompleted(@NonNull PersistableBundle downloadParams);
+}
diff --git a/core/java/android/app/ondeviceintelligence/Feature.aidl b/core/java/android/app/ondeviceintelligence/Feature.aidl
new file mode 100644
index 0000000..18494d7
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/Feature.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+/**
+  * @hide
+  */
+parcelable Feature;
diff --git a/core/java/android/app/ondeviceintelligence/Feature.java b/core/java/android/app/ondeviceintelligence/Feature.java
new file mode 100644
index 0000000..5107354
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/Feature.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+
+/**
+ * Represents a typical feature associated with on-device intelligence.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public final class Feature implements Parcelable {
+    // TODO(b/325315604) - Check if we can expose non-hidden IntDefs in Framework.
+    private final int mId;
+    @Nullable
+    private final String mName;
+    @Nullable
+    private final String mModelName;
+    private final int mType;
+    private final int mVariant;
+    @NonNull
+    private final PersistableBundle mFeatureParams;
+
+    /* package-private */ Feature(
+            int id,
+            @Nullable String name,
+            @Nullable String modelName,
+            int type,
+            int variant,
+            @NonNull PersistableBundle featureParams) {
+        this.mId = id;
+        this.mName = name;
+        this.mModelName = modelName;
+        this.mType = type;
+        this.mVariant = variant;
+        this.mFeatureParams = featureParams;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFeatureParams);
+    }
+
+    /** Returns the unique and immutable identifier of this feature. */
+    public int getId() {
+        return mId;
+    }
+
+    /** Returns human-readable name of this feature. */
+    public @Nullable String getName() {
+        return mName;
+    }
+
+    /** Returns base model name of this feature. */
+    public @Nullable String getModelName() {
+        return mModelName;
+    }
+
+    /** Returns type identifier of this feature. */
+    public int getType() {
+        return mType;
+    }
+
+    /** Returns variant kind for this feature. */
+    public int getVariant() {
+        return mVariant;
+    }
+
+    public @NonNull PersistableBundle getFeatureParams() {
+        return mFeatureParams;
+    }
+
+    @Override
+    public String toString() {
+        return "Feature { " +
+                "id = " + mId + ", " +
+                "name = " + mName + ", " +
+                "modelName = " + mModelName + ", " +
+                "type = " + mType + ", " +
+                "variant = " + mVariant + ", " +
+                "featureParams = " + mFeatureParams +
+                " }";
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        Feature that = (Feature) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mId == that.mId
+                && java.util.Objects.equals(mName, that.mName)
+                && java.util.Objects.equals(mModelName, that.mModelName)
+                && mType == that.mType
+                && mVariant == that.mVariant
+                && java.util.Objects.equals(mFeatureParams, that.mFeatureParams);
+    }
+
+    @Override
+    public int hashCode() {
+        int _hash = 1;
+        _hash = 31 * _hash + mId;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mName);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mModelName);
+        _hash = 31 * _hash + mType;
+        _hash = 31 * _hash + mVariant;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureParams);
+        return _hash;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        byte flg = 0;
+        if (mName != null) flg |= 0x2;
+        if (mModelName != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeInt(mId);
+        if (mName != null) dest.writeString8(mName);
+        if (mModelName != null) dest.writeString8(mModelName);
+        dest.writeInt(mType);
+        dest.writeInt(mVariant);
+        dest.writeTypedObject(mFeatureParams, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    /* package-private */ Feature(@NonNull Parcel in) {
+        byte flg = in.readByte();
+        int id = in.readInt();
+        String name = (flg & 0x2) == 0 ? null : in.readString();
+        String modelName = (flg & 0x4) == 0 ? null : in.readString();
+        int type = in.readInt();
+        int variant = in.readInt();
+        PersistableBundle featureParams = (PersistableBundle) in.readTypedObject(
+                PersistableBundle.CREATOR);
+
+        this.mId = id;
+        this.mName = name;
+        this.mModelName = modelName;
+        this.mType = type;
+        this.mVariant = variant;
+        this.mFeatureParams = featureParams;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFeatureParams);
+    }
+
+    public static final @NonNull Parcelable.Creator<Feature> CREATOR
+            = new Parcelable.Creator<Feature>() {
+        @Override
+        public Feature[] newArray(int size) {
+            return new Feature[size];
+        }
+
+        @Override
+        public Feature createFromParcel(@NonNull Parcel in) {
+            return new Feature(in);
+        }
+    };
+
+    /**
+     * A builder for {@link Feature}
+     */
+    @SuppressWarnings("WeakerAccess")
+    public static final class Builder {
+        private int mId;
+        private @Nullable String mName;
+        private @Nullable String mModelName;
+        private int mType;
+        private int mVariant;
+        private @NonNull PersistableBundle mFeatureParams;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(
+                int id,
+                int type,
+                int variant,
+                @NonNull PersistableBundle featureParams) {
+            mId = id;
+            mType = type;
+            mVariant = variant;
+            mFeatureParams = featureParams;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mFeatureParams);
+        }
+
+        public @NonNull Builder setId(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mId = value;
+            return this;
+        }
+
+        public @NonNull Builder setName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mName = value;
+            return this;
+        }
+
+        public @NonNull Builder setModelName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mModelName = value;
+            return this;
+        }
+
+        public @NonNull Builder setType(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mType = value;
+            return this;
+        }
+
+        public @NonNull Builder setVariant(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mVariant = value;
+            return this;
+        }
+
+        public @NonNull Builder setFeatureParams(@NonNull PersistableBundle value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mFeatureParams = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull Feature build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40; // Mark builder used
+
+            Feature o = new Feature(
+                    mId,
+                    mName,
+                    mModelName,
+                    mType,
+                    mVariant,
+                    mFeatureParams);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x40) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/ondeviceintelligence/FeatureDetails.aidl b/core/java/android/app/ondeviceintelligence/FeatureDetails.aidl
new file mode 100644
index 0000000..0589bf8
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/FeatureDetails.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+/**
+  * @hide
+  */
+parcelable FeatureDetails;
diff --git a/core/java/android/app/ondeviceintelligence/FeatureDetails.java b/core/java/android/app/ondeviceintelligence/FeatureDetails.java
new file mode 100644
index 0000000..92f3513
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/FeatureDetails.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.text.MessageFormat;
+
+/**
+ * Represents a status of a requested {@link Feature}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public final class FeatureDetails implements Parcelable {
+    @Status
+    private final int mStatus;
+    @NonNull
+    private final PersistableBundle mFeatureDetailParams;
+
+    /** Invalid or unavailable {@code AiFeature}. */
+    public static final int FEATURE_STATUS_UNAVAILABLE = 0;
+
+    /** Feature can be downloaded on request. */
+    public static final int FEATURE_STATUS_DOWNLOADABLE = 1;
+
+    /** Feature is being downloaded. */
+    public static final int FEATURE_STATUS_DOWNLOADING = 2;
+
+    /** Feature is fully downloaded and ready to use. */
+    public static final int FEATURE_STATUS_AVAILABLE = 3;
+
+    /** Underlying service is unavailable and feature status cannot be fetched. */
+    public static final int FEATURE_STATUS_SERVICE_UNAVAILABLE = 4;
+
+    @IntDef(value = {
+            FEATURE_STATUS_UNAVAILABLE,
+            FEATURE_STATUS_DOWNLOADABLE,
+            FEATURE_STATUS_DOWNLOADING,
+            FEATURE_STATUS_AVAILABLE,
+            FEATURE_STATUS_SERVICE_UNAVAILABLE
+    }, open = true)
+    @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Status {
+    }
+
+    public FeatureDetails(
+            @Status int status,
+            @NonNull PersistableBundle featureDetailParams) {
+        this.mStatus = status;
+        com.android.internal.util.AnnotationValidations.validate(
+                Status.class, null, mStatus);
+        this.mFeatureDetailParams = featureDetailParams;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFeatureDetailParams);
+    }
+
+    public FeatureDetails(
+            @Status int status) {
+        this.mStatus = status;
+        com.android.internal.util.AnnotationValidations.validate(
+                Status.class, null, mStatus);
+        this.mFeatureDetailParams = new PersistableBundle();
+    }
+
+
+    /**
+     * Returns an integer value associated with the feature status.
+     */
+    public @Status int getStatus() {
+        return mStatus;
+    }
+
+
+    /**
+     * Returns a persistable bundle contain any additional status related params.
+     */
+    public @NonNull PersistableBundle getFeatureDetailParams() {
+        return mFeatureDetailParams;
+    }
+
+    @Override
+    public String toString() {
+        return MessageFormat.format("FeatureDetails '{' status = {0}, "
+                        + "persistableBundle = {1} '}'",
+                mStatus,
+                mFeatureDetailParams);
+    }
+
+    @Override
+    public boolean equals(@android.annotation.Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        FeatureDetails that = (FeatureDetails) o;
+        return mStatus == that.mStatus
+                && java.util.Objects.equals(mFeatureDetailParams, that.mFeatureDetailParams);
+    }
+
+    @Override
+    public int hashCode() {
+        int _hash = 1;
+        _hash = 31 * _hash + mStatus;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureDetailParams);
+        return _hash;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        dest.writeInt(mStatus);
+        dest.writeTypedObject(mFeatureDetailParams, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    FeatureDetails(@NonNull android.os.Parcel in) {
+        int status = in.readInt();
+        PersistableBundle persistableBundle = (PersistableBundle) in.readTypedObject(
+                PersistableBundle.CREATOR);
+
+        this.mStatus = status;
+        com.android.internal.util.AnnotationValidations.validate(
+                Status.class, null, mStatus);
+        this.mFeatureDetailParams = persistableBundle;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mFeatureDetailParams);
+    }
+
+
+    public static final @NonNull Parcelable.Creator<FeatureDetails> CREATOR =
+            new Parcelable.Creator<>() {
+                @Override
+                public FeatureDetails[] newArray(int size) {
+                    return new FeatureDetails[size];
+                }
+
+                @Override
+                public FeatureDetails createFromParcel(@NonNull android.os.Parcel in) {
+                    return new FeatureDetails(in);
+                }
+            };
+
+}
diff --git a/core/java/android/app/ondeviceintelligence/FilePart.java b/core/java/android/app/ondeviceintelligence/FilePart.java
new file mode 100644
index 0000000..e9fb5f2
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/FilePart.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+
+import android.annotation.NonNull;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Represents file data with an associated file descriptor sent to and received from remote
+ * processing. The interface ensures that the underlying file-descriptor is always opened in
+ * read-only mode.
+ *
+ * @hide
+ */
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+@SystemApi
+public final class FilePart implements Parcelable {
+    private final String mPartKey;
+    private final PersistableBundle mPartParams;
+    private final ParcelFileDescriptor mParcelFileDescriptor;
+
+    private FilePart(@NonNull String partKey, @NonNull PersistableBundle partParams,
+            @NonNull ParcelFileDescriptor parcelFileDescriptor) {
+        Objects.requireNonNull(partKey);
+        Objects.requireNonNull(partParams);
+        this.mPartKey = partKey;
+        this.mPartParams = partParams;
+        this.mParcelFileDescriptor = Objects.requireNonNull(parcelFileDescriptor);
+    }
+
+    /**
+     * Create a file part using a filePath and any additional params.
+     */
+    public FilePart(@NonNull String partKey, @NonNull PersistableBundle partParams,
+            @NonNull String filePath)
+            throws FileNotFoundException {
+        this(partKey, partParams, Objects.requireNonNull(ParcelFileDescriptor.open(
+                new File(Objects.requireNonNull(filePath)), ParcelFileDescriptor.MODE_READ_ONLY)));
+    }
+
+    /**
+     * Create a file part using a file input stream and any additional params.
+     * It is the caller's responsibility to close the stream. It is safe to do so as soon as this
+     * call returns.
+     */
+    public FilePart(@NonNull String partKey, @NonNull PersistableBundle partParams,
+            @NonNull FileInputStream fileInputStream)
+            throws IOException {
+        this(partKey, partParams, ParcelFileDescriptor.dup(fileInputStream.getFD()));
+    }
+
+    /**
+     * Returns a FileInputStream for the associated File.
+     * Caller must close the associated stream when done reading from it.
+     *
+     * @return the FileInputStream associated with the FilePart.
+     */
+    @NonNull
+    public FileInputStream getFileInputStream() {
+        return new FileInputStream(mParcelFileDescriptor.getFileDescriptor());
+    }
+
+    /**
+     * Returns the unique key associated with the part. Each Part key added to a content object
+     * should be ensured to be unique.
+     */
+    @NonNull
+    public String getFilePartKey() {
+        return mPartKey;
+    }
+
+    /**
+     * Returns the params associated with Part.
+     */
+    @NonNull
+    public PersistableBundle getFilePartParams() {
+        return mPartParams;
+    }
+
+
+    @Override
+    public int describeContents() {
+        return CONTENTS_FILE_DESCRIPTOR;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(getFilePartKey());
+        dest.writePersistableBundle(getFilePartParams());
+        mParcelFileDescriptor.writeToParcel(dest, flags
+                | Parcelable.PARCELABLE_WRITE_RETURN_VALUE); // This flag ensures that the sender's
+        // copy of the Pfd is closed as soon as the Binder call succeeds.
+    }
+
+    @NonNull
+    public static final Creator<FilePart> CREATOR = new Creator<>() {
+        @Override
+        public FilePart createFromParcel(Parcel in) {
+            return new FilePart(in.readString(), in.readTypedObject(PersistableBundle.CREATOR),
+                    in.readParcelable(
+                            getClass().getClassLoader(), ParcelFileDescriptor.class));
+        }
+
+        @Override
+        public FilePart[] newArray(int size) {
+            return new FilePart[size];
+        }
+    };
+}
diff --git a/core/java/android/app/ondeviceintelligence/IDownloadCallback.aidl b/core/java/android/app/ondeviceintelligence/IDownloadCallback.aidl
new file mode 100644
index 0000000..aba563f
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IDownloadCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.IProcessingSignal;
+import android.os.PersistableBundle;
+
+/**
+ * Interface for Download callback to passed onto service implementation,
+ *
+ * @hide
+ */
+oneway interface IDownloadCallback {
+  void onDownloadStarted(long bytesToDownload) = 1;
+  void onDownloadProgress(long bytesDownloaded) = 2;
+  void onDownloadFailed(int failureStatus, String errorMessage, in PersistableBundle errorParams) = 3;
+  void onDownloadCompleted(in PersistableBundle downloadParams) = 4;
+}
\ No newline at end of file
diff --git a/core/java/android/app/ondeviceintelligence/IFeatureCallback.aidl b/core/java/android/app/ondeviceintelligence/IFeatureCallback.aidl
new file mode 100644
index 0000000..93a84ec
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IFeatureCallback.aidl
@@ -0,0 +1,14 @@
+package android.app.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.Feature;
+import android.os.PersistableBundle;
+
+/**
+  * Interface for receiving a feature for the given identifier.
+  *
+  * @hide
+  */
+interface IFeatureCallback {
+    void onSuccess(in Feature result) = 1;
+    void onFailure(int errorCode, in String errorMessage, in PersistableBundle errorParams) = 2;
+}
diff --git a/core/java/android/app/ondeviceintelligence/IFeatureDetailsCallback.aidl b/core/java/android/app/ondeviceintelligence/IFeatureDetailsCallback.aidl
new file mode 100644
index 0000000..d950290
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IFeatureDetailsCallback.aidl
@@ -0,0 +1,14 @@
+package android.app.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.FeatureDetails;
+import android.os.PersistableBundle;
+
+/**
+  * Interface for receiving details about a given feature. .
+  *
+  * @hide
+  */
+interface IFeatureDetailsCallback {
+    void onSuccess(in FeatureDetails result) = 1;
+    void onFailure(int errorCode, in String errorMessage, in PersistableBundle errorParams) = 2;
+}
diff --git a/core/java/android/app/ondeviceintelligence/IListFeaturesCallback.aidl b/core/java/android/app/ondeviceintelligence/IListFeaturesCallback.aidl
new file mode 100644
index 0000000..374cb71
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IListFeaturesCallback.aidl
@@ -0,0 +1,15 @@
+package android.app.ondeviceintelligence;
+
+import java.util.List;
+import android.app.ondeviceintelligence.Feature;
+import android.os.PersistableBundle;
+
+/**
+  * Interface for receiving list of supported features.
+  *
+  * @hide
+  */
+interface IListFeaturesCallback {
+    void onSuccess(in List<Feature> result) = 1;
+    void onFailure(int errorCode, in String errorMessage, in PersistableBundle errorParams) = 2;
+}
diff --git a/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl b/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl
new file mode 100644
index 0000000..b925f48
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IOnDeviceIntelligenceManager.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+ import com.android.internal.infra.AndroidFuture;
+ import android.os.ICancellationSignal;
+ import android.os.ParcelFileDescriptor;
+ import android.os.PersistableBundle;
+ import android.os.RemoteCallback;
+ import android.app.ondeviceintelligence.Content;
+ import android.app.ondeviceintelligence.Feature;
+ import android.app.ondeviceintelligence.FeatureDetails;
+ import android.app.ondeviceintelligence.IDownloadCallback;
+ import android.app.ondeviceintelligence.IListFeaturesCallback;
+ import android.app.ondeviceintelligence.IFeatureCallback;
+ import android.app.ondeviceintelligence.IFeatureDetailsCallback;
+ import android.app.ondeviceintelligence.IResponseCallback;
+ import android.app.ondeviceintelligence.IStreamingResponseCallback;
+ import android.app.ondeviceintelligence.IProcessingSignal;
+ import android.app.ondeviceintelligence.ITokenCountCallback;
+
+
+ /**
+  * Interface for a OnDeviceIntelligenceManager for managing OnDeviceIntelligenceService and OnDeviceSandboxedInferenceService.
+  *
+  * @hide
+  */
+ oneway interface IOnDeviceIntelligenceManager {
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void getVersion(in RemoteCallback remoteCallback) = 1;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void getFeature(in int featureId, in IFeatureCallback remoteCallback) = 2;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void listFeatures(in IListFeaturesCallback listFeaturesCallback) = 3;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void getFeatureDetails(in Feature feature, in IFeatureDetailsCallback featureDetailsCallback) = 4;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void requestFeatureDownload(in Feature feature, ICancellationSignal signal, in IDownloadCallback callback) = 5;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void requestTokenCount(in Feature feature, in Content request, in  ICancellationSignal signal,
+                                                        in ITokenCountCallback tokenCountcallback) = 6;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void processRequest(in Feature feature, in Content request, int requestType, in  ICancellationSignal cancellationSignal, in IProcessingSignal signal,
+                                                        in IResponseCallback responseCallback) = 7;
+
+      @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)")
+      void processRequestStreaming(in Feature feature,
+                    in Content request, int requestType, in  ICancellationSignal cancellationSignal, in  IProcessingSignal signal,
+                    in IStreamingResponseCallback streamingCallback) = 8;
+ }
diff --git a/core/java/android/app/ondeviceintelligence/IProcessingSignal.aidl b/core/java/android/app/ondeviceintelligence/IProcessingSignal.aidl
new file mode 100644
index 0000000..03946ee
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IProcessingSignal.aidl
@@ -0,0 +1,14 @@
+package android.app.ondeviceintelligence;
+
+import android.os.PersistableBundle;
+
+/**
+* Signal to provide to the remote implementation in context of a given request or
+* feature specific event.
+*
+* @hide
+*/
+
+oneway interface IProcessingSignal {
+    void sendSignal(in PersistableBundle actionParams) = 2;
+}
diff --git a/core/java/android/app/ondeviceintelligence/IResponseCallback.aidl b/core/java/android/app/ondeviceintelligence/IResponseCallback.aidl
new file mode 100644
index 0000000..9848e1d
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IResponseCallback.aidl
@@ -0,0 +1,15 @@
+package android.app.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.Content;
+import android.app.ondeviceintelligence.IProcessingSignal;
+import android.os.PersistableBundle;
+
+/**
+  * Interface for a IResponseCallback for receiving response from on-device intelligence service.
+  *
+  * @hide
+  */
+interface IResponseCallback {
+    void onSuccess(in Content result) = 1;
+    void onFailure(int errorCode, in String errorMessage, in PersistableBundle errorParams) = 2;
+}
diff --git a/core/java/android/app/ondeviceintelligence/IStreamingResponseCallback.aidl b/core/java/android/app/ondeviceintelligence/IStreamingResponseCallback.aidl
new file mode 100644
index 0000000..a680574
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/IStreamingResponseCallback.aidl
@@ -0,0 +1,18 @@
+package android.app.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.Content;
+import android.app.ondeviceintelligence.IResponseCallback;
+import android.app.ondeviceintelligence.IProcessingSignal;
+import android.os.PersistableBundle;
+
+
+/**
+  * This callback is a streaming variant of {@link IResponseCallback}.
+  *
+  * @hide
+  */
+interface IStreamingResponseCallback {
+    void onNewContent(in Content result) = 1;
+    void onSuccess(in Content result) = 2;
+    void onFailure(int errorCode, in String errorMessage, in PersistableBundle errorParams) = 3;
+}
diff --git a/core/java/android/app/ondeviceintelligence/ITokenCountCallback.aidl b/core/java/android/app/ondeviceintelligence/ITokenCountCallback.aidl
new file mode 100644
index 0000000..b724e03
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/ITokenCountCallback.aidl
@@ -0,0 +1,13 @@
+package android.app.ondeviceintelligence;
+
+import android.os.PersistableBundle;
+
+/**
+  * Interface for receiving the token count of a request for a given features.
+  *
+  * @hide
+  */
+interface ITokenCountCallback {
+    void onSuccess(long tokenCount) = 1;
+    void onFailure(int errorCode, in String errorMessage, in PersistableBundle errorParams) = 2;
+}
diff --git a/core/java/android/app/ondeviceintelligence/OWNERS b/core/java/android/app/ondeviceintelligence/OWNERS
index 6932ba2..85e9e65 100644
--- a/core/java/android/app/ondeviceintelligence/OWNERS
+++ b/core/java/android/app/ondeviceintelligence/OWNERS
@@ -4,4 +4,3 @@
 shivanker@google.com
 hackz@google.com
 volnov@google.com
-
diff --git a/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
new file mode 100644
index 0000000..4d8e0d5
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/OnDeviceIntelligenceManager.java
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.Binder;
+import android.os.CancellationSignal;
+import android.os.ICancellationSignal;
+import android.os.OutcomeReceiver;
+import android.os.PersistableBundle;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.LongConsumer;
+
+/**
+ * Allows granted apps to manage on-device intelligence service configured on the device. Typical
+ * calling pattern will be to query and setup a required feature before proceeding to request
+ * processing.
+ *
+ * The contracts in this Manager class are designed to be open-ended in general, to allow
+ * interoperability. Therefore, it is recommended that implementations of this system-service
+ * expose this API to the clients via a separate sdk or library which has more defined contract.
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.ON_DEVICE_INTELLIGENCE_SERVICE)
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public class OnDeviceIntelligenceManager {
+    public static final String API_VERSION_BUNDLE_KEY = "ApiVersionBundleKey";
+    private final Context mContext;
+    private final IOnDeviceIntelligenceManager mService;
+
+    /**
+     * @hide
+     */
+    public OnDeviceIntelligenceManager(Context context, IOnDeviceIntelligenceManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Asynchronously get the version of the underlying remote implementation.
+     *
+     * @param versionConsumer  consumer to populate the version of remote implementation.
+     * @param callbackExecutor executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void getVersion(
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull LongConsumer versionConsumer) {
+        // TODO explore modifying this method into getServicePackageDetails and return both
+        //  version and package name of the remote service implementing this.
+        try {
+            RemoteCallback callback = new RemoteCallback(result -> {
+                if (result == null) {
+                    Binder.withCleanCallingIdentity(
+                            () -> callbackExecutor.execute(() -> versionConsumer.accept(0)));
+                }
+                long version = result.getLong(API_VERSION_BUNDLE_KEY);
+                Binder.withCleanCallingIdentity(
+                        () -> callbackExecutor.execute(() -> versionConsumer.accept(version)));
+            });
+            mService.getVersion(callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Asynchronously get feature for a given id.
+     *
+     * @param featureId        the identifier pointing to the feature.
+     * @param featureReceiver  callback to populate the feature object for given identifier.
+     * @param callbackExecutor executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void getFeature(
+            int featureId,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull OutcomeReceiver<Feature, OnDeviceIntelligenceManagerException> featureReceiver) {
+        try {
+            IFeatureCallback callback =
+                    new IFeatureCallback.Stub() {
+                        @Override
+                        public void onSuccess(Feature result) {
+                            Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                                    () -> featureReceiver.onResult(result)));
+                        }
+
+                        @Override
+                        public void onFailure(int errorCode, String errorMessage,
+                                PersistableBundle errorParams) {
+                            Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                                    () -> featureReceiver.onError(
+                                            new OnDeviceIntelligenceManagerException(
+                                                    errorCode, errorMessage, errorParams))));
+                        }
+                    };
+            mService.getFeature(featureId, callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Asynchronously get a list of features that are supported for the caller.
+     *
+     * @param featureListReceiver callback to populate the list of features.
+     * @param callbackExecutor    executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void listFeatures(
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull OutcomeReceiver<List<Feature>, OnDeviceIntelligenceManagerException> featureListReceiver) {
+        try {
+            IListFeaturesCallback callback =
+                    new IListFeaturesCallback.Stub() {
+                        @Override
+                        public void onSuccess(List<Feature> result) {
+                            Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                                    () -> featureListReceiver.onResult(result)));
+                        }
+
+                        @Override
+                        public void onFailure(int errorCode, String errorMessage,
+                                PersistableBundle errorParams) {
+                            Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                                    () -> featureListReceiver.onError(
+                                            new OnDeviceIntelligenceManagerException(
+                                                    errorCode, errorMessage, errorParams))));
+                        }
+                    };
+            mService.listFeatures(callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * This method should be used to fetch details about a feature which need some additional
+     * computation, that can be inefficient to return in all calls to {@link #getFeature}. Callers
+     * and implementation can utilize the {@link Feature#getFeatureParams()} to pass hint on what
+     * details are expected by the caller.
+     *
+     * @param feature                the feature to check status for.
+     * @param featureDetailsReceiver callback to populate the feature details to.
+     * @param callbackExecutor       executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void getFeatureDetails(@NonNull Feature feature,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull OutcomeReceiver<FeatureDetails, OnDeviceIntelligenceManagerException> featureDetailsReceiver) {
+        try {
+            IFeatureDetailsCallback callback = new IFeatureDetailsCallback.Stub() {
+
+                @Override
+                public void onSuccess(FeatureDetails result) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> featureDetailsReceiver.onResult(result)));
+                }
+
+                @Override
+                public void onFailure(int errorCode, String errorMessage,
+                        PersistableBundle errorParams) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> featureDetailsReceiver.onError(
+                                    new OnDeviceIntelligenceManagerException(errorCode,
+                                            errorMessage, errorParams))));
+                }
+            };
+            mService.getFeatureDetails(feature, callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * This method handles downloading all model and config files required to process requests
+     * sent against a given feature. The caller can listen to updates on the download status via
+     * the callback.
+     *
+     * Note: If a feature was already requested for downloaded previously, the onDownloadFailed
+     * callback would be invoked with {@link DownloadCallback#DOWNLOAD_FAILURE_STATUS_DOWNLOADING}.
+     * In such cases, clients should query the feature status via {@link #getFeatureStatus} to
+     * check
+     * on the feature's download status.
+     *
+     * @param feature            feature to request download for.
+     * @param callback           callback to populate updates about download status.
+     * @param cancellationSignal signal to invoke cancellation on the operation in the remote
+     *                           implementation.
+     * @param callbackExecutor   executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void requestFeatureDownload(@NonNull Feature feature,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull DownloadCallback callback) {
+        try {
+            IDownloadCallback downloadCallback = new IDownloadCallback.Stub() {
+
+                @Override
+                public void onDownloadStarted(long bytesToDownload) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> callback.onDownloadStarted(bytesToDownload)));
+                }
+
+                @Override
+                public void onDownloadProgress(long bytesDownloaded) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> callback.onDownloadProgress(bytesDownloaded)));
+                }
+
+                @Override
+                public void onDownloadFailed(int failureStatus, String errorMessage,
+                        PersistableBundle errorParams) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> callback.onDownloadFailed(failureStatus, errorMessage,
+                                    errorParams)));
+                }
+
+                @Override
+                public void onDownloadCompleted(PersistableBundle downloadParams) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> onDownloadCompleted(downloadParams)));
+                }
+            };
+
+            ICancellationSignal transport = null;
+            if (cancellationSignal != null) {
+                transport = CancellationSignal.createTransport();
+                cancellationSignal.setRemote(transport);
+            }
+
+            mService.requestFeatureDownload(feature, transport, downloadCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * The methods computes the token-count for a given request payload using the provided Feature
+     * details.
+     *
+     * @param feature            feature associated with the request.
+     * @param request            request that contains the content data and associated params.
+     * @param outcomeReceiver    callback to populate the token count or exception in case of
+     *                           failure.
+     * @param cancellationSignal signal to invoke cancellation on the operation in the remote
+     *                           implementation.
+     * @param callbackExecutor   executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void requestTokenCount(@NonNull Feature feature, @NonNull Content request,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull OutcomeReceiver<Long,
+                    OnDeviceIntelligenceManagerException> outcomeReceiver) {
+        try {
+            ITokenCountCallback callback = new ITokenCountCallback.Stub() {
+                @Override
+                public void onSuccess(long tokenCount) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> outcomeReceiver.onResult(tokenCount)));
+                }
+
+                @Override
+                public void onFailure(int errorCode, String errorMessage,
+                        PersistableBundle errorParams) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> outcomeReceiver.onError(
+                                    new OnDeviceIntelligenceManagerProcessingException(
+                                            errorCode, errorMessage, errorParams))));
+                }
+            };
+
+            ICancellationSignal transport = null;
+            if (cancellationSignal != null) {
+                transport = CancellationSignal.createTransport();
+                cancellationSignal.setRemote(transport);
+            }
+
+            mService.requestTokenCount(feature, request, transport, callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
+    /**
+     * Asynchronously Process a request based on the associated params, to populate a
+     * response in
+     * {@link OutcomeReceiver#onResult} callback or failure callback status code if there
+     * was a
+     * failure.
+     *
+     * @param feature                 feature associated with the request.
+     * @param request                 request that contains the Content data and
+     *                                associated params.
+     * @param requestType             type of request being sent for processing the content.
+     * @param responseOutcomeReceiver callback to populate the response content and
+     *                                associated
+     *                                params.
+     * @param processingSignal        signal to invoke custom actions in the
+     *                                remote implementation.
+     * @param cancellationSignal      signal to invoke cancellation or
+     * @param callbackExecutor        executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+
+    public void processRequest(@NonNull Feature feature, @NonNull Content request,
+            @RequestType int requestType,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable ProcessingSignal processingSignal,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull OutcomeReceiver<Content,
+                    OnDeviceIntelligenceManagerProcessingException> responseOutcomeReceiver) {
+        try {
+            IResponseCallback callback = new IResponseCallback.Stub() {
+                @Override
+                public void onSuccess(Content result) {
+                    Binder.withCleanCallingIdentity(() -> {
+                        callbackExecutor.execute(() -> responseOutcomeReceiver.onResult(result));
+                    });
+                }
+
+                @Override
+                public void onFailure(int errorCode, String errorMessage,
+                        PersistableBundle errorParams) {
+                    Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                            () -> responseOutcomeReceiver.onError(
+                                    new OnDeviceIntelligenceManagerProcessingException(
+                                            errorCode, errorMessage, errorParams))));
+                }
+            };
+
+            IProcessingSignal transport = null;
+            if (processingSignal != null) {
+                transport = ProcessingSignal.createTransport();
+                processingSignal.setRemote(transport);
+            }
+
+            ICancellationSignal cancellationTransport = null;
+            if (cancellationSignal != null) {
+                cancellationTransport = CancellationSignal.createTransport();
+                cancellationSignal.setRemote(cancellationTransport);
+            }
+
+            mService.processRequest(feature, request, requestType, cancellationTransport, transport,
+                    callback);
+
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Variation of {@link #processRequest} that asynchronously processes a request in a streaming
+     * fashion, where new content is pushed to caller in chunks via the
+     * {@link StreamingResponseReceiver#onNewContent}. After the streaming is complete,
+     * the service should call {@link StreamingResponseReceiver#onResult} and can optionally
+     * populate the complete {@link Response}'s Content as part of the callback when the final
+     * {@link Response} contains an enhanced aggregation of the Contents already streamed.
+     *
+     * @param feature                   feature associated with the request.
+     * @param request                   request that contains the Content data and associated
+     *                                  params.
+     * @param requestType               type of request being sent for processing the content.
+     * @param processingSignal          signal to invoke  other custom actions in the
+     *                                  remote implementation.
+     * @param cancellationSignal        signal to invoke cancellation
+     * @param streamingResponseReceiver streaming callback to populate the response content and
+     *                                  associated params.
+     * @param callbackExecutor          executor to run the callback on.
+     */
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void processRequestStreaming(@NonNull Feature feature, @NonNull Content request,
+            @RequestType int requestType,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable ProcessingSignal processingSignal,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull StreamingResponseReceiver<Content, Content,
+                    OnDeviceIntelligenceManagerProcessingException> streamingResponseReceiver) {
+        try {
+            IStreamingResponseCallback callback = new IStreamingResponseCallback.Stub() {
+                @Override
+                public void onNewContent(Content result) {
+                    Binder.withCleanCallingIdentity(() -> {
+                        callbackExecutor.execute(
+                                () -> streamingResponseReceiver.onNewContent(result));
+                    });
+                }
+
+                @Override
+                public void onSuccess(Content result) {
+                    Binder.withCleanCallingIdentity(() -> {
+                        callbackExecutor.execute(() -> streamingResponseReceiver.onResult(result));
+                    });
+                }
+
+                @Override
+                public void onFailure(int errorCode, String errorMessage,
+                        PersistableBundle errorParams) {
+                    Binder.withCleanCallingIdentity(() -> {
+                        callbackExecutor.execute(
+                                () -> streamingResponseReceiver.onError(
+                                        new OnDeviceIntelligenceManagerProcessingException(
+                                                errorCode, errorMessage, errorParams)));
+                    });
+                }
+            };
+
+            IProcessingSignal transport = null;
+            if (processingSignal != null) {
+                transport = ProcessingSignal.createTransport();
+                processingSignal.setRemote(transport);
+            }
+
+            ICancellationSignal cancellationTransport = null;
+            if (cancellationSignal != null) {
+                cancellationTransport = CancellationSignal.createTransport();
+                cancellationSignal.setRemote(cancellationTransport);
+            }
+
+            mService.processRequestStreaming(
+                    feature, request, requestType, cancellationTransport, transport, callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
+    /** Request inference with provided Content and Params. */
+    public static final int REQUEST_TYPE_INFERENCE = 0;
+
+    /**
+     * Prepares the remote implementation environment for e.g.loading inference runtime etc.which
+     * are time consuming beforehand to remove overhead and allow quick processing of requests
+     * thereof.
+     */
+    public static final int REQUEST_TYPE_PREPARE = 1;
+
+    /** Request Embeddings of the passed-in Content. */
+    public static final int REQUEST_TYPE_EMBEDDINGS = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef(value = {
+            REQUEST_TYPE_INFERENCE,
+            REQUEST_TYPE_PREPARE,
+            REQUEST_TYPE_EMBEDDINGS
+    }, open = true)
+    @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RequestType {
+    }
+
+
+    /**
+     * Exception type to be populated in callbacks to the methods under
+     * {@link OnDeviceIntelligenceManager}.
+     */
+    public static class OnDeviceIntelligenceManagerException extends Exception {
+        /**
+         * Error code returned when the OnDeviceIntelligenceManager service is unavailable.
+         */
+        public static final int ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE = 1000;
+
+        private final int mErrorCode;
+        private final PersistableBundle errorParams;
+
+        public OnDeviceIntelligenceManagerException(int errorCode, @NonNull String errorMessage,
+                @NonNull PersistableBundle errorParams) {
+            super(errorMessage);
+            this.mErrorCode = errorCode;
+            this.errorParams = errorParams;
+        }
+
+        public OnDeviceIntelligenceManagerException(int errorCode,
+                @NonNull PersistableBundle errorParams) {
+            this.mErrorCode = errorCode;
+            this.errorParams = errorParams;
+        }
+
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        @NonNull
+        public PersistableBundle getErrorParams() {
+            return errorParams;
+        }
+    }
+
+    /**
+     * Exception type to be populated in callbacks to the methods under
+     * {@link OnDeviceIntelligenceManager#processRequest} or
+     * {@link OnDeviceIntelligenceManager#processRequestStreaming} .
+     */
+    public static class OnDeviceIntelligenceManagerProcessingException extends
+            OnDeviceIntelligenceManagerException {
+
+        public static final int PROCESSING_ERROR_UNKNOWN = 1;
+
+        /** Request passed contains bad data for e.g. format. */
+        public static final int PROCESSING_ERROR_BAD_DATA = 2;
+
+        /** Bad request for inputs. */
+        public static final int PROCESSING_ERROR_BAD_REQUEST = 3;
+
+        /** Whole request was classified as not safe, and no response will be generated. */
+        public static final int PROCESSING_ERROR_REQUEST_NOT_SAFE = 4;
+
+        /** Underlying processing encountered an error and failed to compute results. */
+        public static final int PROCESSING_ERROR_COMPUTE_ERROR = 5;
+
+        /** Encountered an error while performing IPC */
+        public static final int PROCESSING_ERROR_IPC_ERROR = 6;
+
+        /** Request was cancelled either by user signal or by the underlying implementation. */
+        public static final int PROCESSING_ERROR_CANCELLED = 7;
+
+        /** Underlying processing in the remote implementation is not available. */
+        public static final int PROCESSING_ERROR_NOT_AVAILABLE = 8;
+
+        /** The service is currently busy. Callers should retry with exponential backoff. */
+        public static final int PROCESSING_ERROR_BUSY = 9;
+
+        /** Something went wrong with safety classification service. */
+        public static final int PROCESSING_ERROR_SAFETY_ERROR = 10;
+
+        /** Response generated was classified unsafe. */
+        public static final int PROCESSING_ERROR_RESPONSE_NOT_SAFE = 11;
+
+        /** Request is too large to be processed. */
+        public static final int PROCESSING_ERROR_REQUEST_TOO_LARGE = 12;
+
+        /** Inference suspended so that higher-priority inference can run. */
+        public static final int PROCESSING_ERROR_SUSPENDED = 13;
+
+        /** Underlying processing encountered an internal error, like a violated precondition. */
+        public static final int PROCESSING_ERROR_INTERNAL = 14;
+
+        /**
+         * The processing was not able to be passed on to the remote implementation, as the service
+         * was unavailable.
+         */
+        public static final int PROCESSING_ERROR_SERVICE_UNAVAILABLE = 15;
+
+        /**
+         * Error code of failed processing request.
+         *
+         * @hide
+         */
+        @IntDef(
+                value = {
+                        PROCESSING_ERROR_UNKNOWN,
+                        PROCESSING_ERROR_BAD_DATA,
+                        PROCESSING_ERROR_BAD_REQUEST,
+                        PROCESSING_ERROR_REQUEST_NOT_SAFE,
+                        PROCESSING_ERROR_COMPUTE_ERROR,
+                        PROCESSING_ERROR_IPC_ERROR,
+                        PROCESSING_ERROR_CANCELLED,
+                        PROCESSING_ERROR_NOT_AVAILABLE,
+                        PROCESSING_ERROR_BUSY,
+                        PROCESSING_ERROR_SAFETY_ERROR,
+                        PROCESSING_ERROR_RESPONSE_NOT_SAFE,
+                        PROCESSING_ERROR_REQUEST_TOO_LARGE,
+                        PROCESSING_ERROR_SUSPENDED,
+                        PROCESSING_ERROR_INTERNAL,
+                        PROCESSING_ERROR_SERVICE_UNAVAILABLE
+                }, open = true)
+        @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+        @interface ProcessingError {
+        }
+
+        public OnDeviceIntelligenceManagerProcessingException(
+                @ProcessingError int errorCode, @NonNull String errorMessage,
+                @NonNull PersistableBundle errorParams) {
+            super(errorCode, errorMessage, errorParams);
+        }
+
+        public OnDeviceIntelligenceManagerProcessingException(
+                @ProcessingError int errorCode,
+                @NonNull PersistableBundle errorParams) {
+            super(errorCode, errorParams);
+        }
+    }
+}
diff --git a/core/java/android/app/ondeviceintelligence/ProcessingSignal.java b/core/java/android/app/ondeviceintelligence/ProcessingSignal.java
new file mode 100644
index 0000000..3e543d2
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/ProcessingSignal.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayDeque;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * A signal to perform orchestration actions on the inference and optionally receive a output about
+ * the result of the signal. This is an extension of {@link android.os.CancellationSignal}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public final class ProcessingSignal {
+    private final Object mLock = new Object();
+
+    private static final int MAX_QUEUE_SIZE = 10;
+
+    @GuardedBy("mLock")
+    private final ArrayDeque<PersistableBundle> mActionParamsQueue;
+
+    @GuardedBy("mLock")
+    private IProcessingSignal mRemote;
+
+    private OnProcessingSignalCallback mOnProcessingSignalCallback;
+    private Executor mExecutor;
+
+    public ProcessingSignal() {
+        mActionParamsQueue = new ArrayDeque<>(MAX_QUEUE_SIZE);
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when processing signals are received.
+     */
+    public interface OnProcessingSignalCallback {
+        /**
+         * Called when a custom signal was received.
+         * This method allows the receiver to provide logic to be executed based on the signal
+         * received.
+         *
+         * @param actionParams Parameters for the signal in the form of a {@link PersistableBundle}.
+         */
+
+        void onSignalReceived(@NonNull PersistableBundle actionParams);
+    }
+
+
+    /**
+     * Sends a custom signal with the provided parameters. It also signals the remote callback
+     * with the same params if already configured, if not the action is queued to be sent when a
+     * remote is configured. Similarly, on the receiver side, the callback will be invoked if
+     * already set, if not all actions are queued to be sent to callback when it is set.
+     *
+     * @param actionParams Parameters for the signal.
+     */
+    public void sendSignal(@NonNull PersistableBundle actionParams) {
+        final OnProcessingSignalCallback callback;
+        final IProcessingSignal remote;
+        synchronized (mLock) {
+            if (mActionParamsQueue.size() > MAX_QUEUE_SIZE) {
+                throw new RuntimeException(
+                        "Maximum actions that can be queued are : " + MAX_QUEUE_SIZE);
+            }
+
+            mActionParamsQueue.add(actionParams);
+            callback = mOnProcessingSignalCallback;
+            remote = mRemote;
+
+            if (callback != null) {
+                while (!mActionParamsQueue.isEmpty()) {
+                    PersistableBundle params = mActionParamsQueue.removeFirst();
+                    mExecutor.execute(
+                            () -> callback.onSignalReceived(params));
+                }
+            }
+            if (remote != null) {
+                while (!mActionParamsQueue.isEmpty()) {
+                    try {
+                        remote.sendSignal(mActionParamsQueue.removeFirst());
+                    } catch (RemoteException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Sets the processing signal callback to be called when signals are received.
+     *
+     * This method is intended to be used by the recipient of a processing signal
+     * such as the remote implementation for {@link OnDeviceIntelligenceManager} to handle
+     * cancellation requests while performing a long-running operation.  This method is not
+     * intended
+     * to be used by applications themselves.
+     *
+     * If {@link ProcessingSignal#sendSignal} has already been called, then the provided callback
+     * is invoked immediately and all previously queued actions are passed to remote signal.
+     *
+     * This method is guaranteed that the callback will not be called after it
+     * has been removed.
+     *
+     * @param callback The processing signal callback, or null to remove the current callback.
+     * @param executor Executor to the run the callback methods on.
+     */
+    public void setOnProcessingSignalCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable OnProcessingSignalCallback callback) {
+        Objects.requireNonNull(executor);
+        synchronized (mLock) {
+            if (mOnProcessingSignalCallback == callback) {
+                return;
+            }
+
+            mOnProcessingSignalCallback = callback;
+            mExecutor = executor;
+            if (callback == null || mActionParamsQueue.isEmpty()) {
+                return;
+            }
+
+            while (!mActionParamsQueue.isEmpty()) {
+                PersistableBundle params = mActionParamsQueue.removeFirst();
+                mExecutor.execute(() -> callback.onSignalReceived(params));
+            }
+        }
+    }
+
+    /**
+     * Sets the remote transport.
+     *
+     * If there are actions queued from {@link ProcessingSignal#sendSignal}, they are also
+     * sequentially sent to the remote.
+     *
+     * This method is guaranteed that the remote transport will not be called after it
+     * has been removed.
+     *
+     * @param remote The remote transport, or null to remove.
+     * @hide
+     */
+    void setRemote(IProcessingSignal remote) {
+        synchronized (mLock) {
+            mRemote = remote;
+            if (mActionParamsQueue.isEmpty() || remote == null) {
+                return;
+            }
+
+            while (!mActionParamsQueue.isEmpty()) {
+                try {
+                    remote.sendSignal(mActionParamsQueue.removeFirst());
+                } catch (RemoteException e) {
+                    throw new RuntimeException("Failed to send action to remote signal", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a transport that can be returned back to the caller of
+     * a Binder function and subsequently used to dispatch a processing signal.
+     *
+     * @return The new processing signal transport.
+     * @hide
+     */
+    public static IProcessingSignal createTransport() {
+        return new Transport();
+    }
+
+    /**
+     * Given a locally created transport, returns its associated cancellation signal.
+     *
+     * @param transport The locally created transport, or null if none.
+     * @return The associated processing signal, or null if none.
+     * @hide
+     */
+    public static ProcessingSignal fromTransport(IProcessingSignal transport) {
+        if (transport instanceof Transport) {
+            return ((Transport) transport).mProcessingSignal;
+        }
+        return null;
+    }
+
+    private static final class Transport extends IProcessingSignal.Stub {
+        final ProcessingSignal mProcessingSignal = new ProcessingSignal();
+
+        @Override
+        public void sendSignal(PersistableBundle actionParams) {
+            mProcessingSignal.sendSignal(actionParams);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/android/app/ondeviceintelligence/StreamingResponseReceiver.java b/core/java/android/app/ondeviceintelligence/StreamingResponseReceiver.java
new file mode 100644
index 0000000..ebcf61c
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/StreamingResponseReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.OutcomeReceiver;
+
+/**
+ * Streaming variant of outcome receiver to populate response while processing a given request,
+ * possibly in
+ * chunks to provide a async processing behaviour to the caller.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public interface StreamingResponseReceiver<R, T, E extends Throwable> extends
+        OutcomeReceiver<R, E> {
+    /**
+     * Callback to be invoked when a part of the response i.e. some {@link Content} is already
+     * processed and
+     * needs to be passed onto the caller.
+     */
+    void onNewContent(@NonNull T content);
+}
diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
new file mode 100644
index 0000000..44f3329
--- /dev/null
+++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
@@ -0,0 +1,8 @@
+package: "android.app.ondeviceintelligence.flags"
+
+flag {
+    name: "enable_on_device_intelligence"
+    namespace: "ondeviceintelligence"
+    description: "Make methods on OnDeviceIntelligenceManager available for local inference."
+    bug: "304755128"
+}
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 612d433..79696e0 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -85,12 +86,15 @@
      * @param item A single message that can contain a client activity/window request/callback.
      */
     public void addTransactionItem(@NonNull ClientTransactionItem item) {
-        if (mTransactionItems == null) {
-            mTransactionItems = new ArrayList<>();
+        if (Flags.bundleClientTransactionFlag()) {
+            if (mTransactionItems == null) {
+                mTransactionItems = new ArrayList<>();
+            }
+            mTransactionItems.add(item);
         }
-        mTransactionItems.add(item);
 
         // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
+        // Populate even if mTransactionItems is set to support the UnsupportedAppUsage.
         if (item.isActivityLifecycleItem()) {
             setLifecycleStateRequest((ActivityLifecycleItem) item);
         } else {
@@ -114,7 +118,7 @@
      */
     // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
     @Deprecated
-    public void addCallback(@NonNull ClientTransactionItem activityCallback) {
+    private void addCallback(@NonNull ClientTransactionItem activityCallback) {
         if (mActivityCallbacks == null) {
             mActivityCallbacks = new ArrayList<>();
         }
@@ -169,7 +173,7 @@
      */
     // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
     @Deprecated
-    public void setLifecycleStateRequest(@NonNull ActivityLifecycleItem stateRequest) {
+    private void setLifecycleStateRequest(@NonNull ActivityLifecycleItem stateRequest) {
         if (mLifecycleStateRequest != null) {
             return;
         }
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index 9f97f6f..1a8136e 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -23,7 +23,6 @@
 import android.annotation.NonNull;
 import android.app.ActivityThread;
 import android.hardware.display.DisplayManagerGlobal;
-import android.os.Process;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -67,7 +66,7 @@
      * window configuration.
      */
     public void onDisplayChanged(int displayId) {
-        if (!isBundleClientTransactionFlagEnabled()) {
+        if (!bundleClientTransactionFlag()) {
             return;
         }
         if (ActivityThread.isSystem()) {
@@ -76,10 +75,4 @@
         }
         mDisplayManager.handleDisplayChangeFromWindowManager(displayId);
     }
-
-    /** Whether {@link #bundleClientTransactionFlag} feature flag is enabled. */
-    public boolean isBundleClientTransactionFlagEnabled() {
-        // Can't read flag from isolated process.
-        return !Process.isIsolated() && bundleClientTransactionFlag();
-    }
 }
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 406e00a..fa73c99 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -40,7 +40,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -218,8 +217,6 @@
         final boolean shouldTrackConfigUpdatedContext =
                 // No configuration change for local transaction.
                 !mTransactionHandler.isExecutingLocalTransaction()
-                        // Can't read flag from isolated process.
-                        && !Process.isIsolated()
                         && bundleClientTransactionFlag();
         final Context configUpdatedContext = shouldTrackConfigUpdatedContext
                 ? item.getContextToUpdate(mTransactionHandler)
diff --git a/core/java/android/app/ui_mode_manager.aconfig b/core/java/android/app/ui_mode_manager.aconfig
index 1ae5264..27a38cc 100644
--- a/core/java/android/app/ui_mode_manager.aconfig
+++ b/core/java/android/app/ui_mode_manager.aconfig
@@ -1,8 +1,11 @@
 package: "android.app"
 
 flag {
-     namespace: "system_performance"
-     name: "enable_night_mode_cache"
+     namespace: "systemui"
+     name: "enable_night_mode_binder_cache"
      description: "Enables the use of binder caching for system night mode."
      bug: "255999432"
+     metadata {
+         purpose: PURPOSE_BUGFIX
+     }
 }
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index ab8db6e..24d6a5c 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -29,3 +29,18 @@
      bug: "291737188"
      is_fixed_read_only: true
 }
+
+flag {
+     namespace: "virtual_devices"
+     name: "metrics_collection"
+     description: "Enable collection of VDM-related metrics"
+     bug: "324842215"
+     is_fixed_read_only: true
+}
+
+flag {
+     namespace: "virtual_devices"
+     name: "camera_device_awareness"
+     description: "Enable device awareness in camera service"
+     bug: "305170199"
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9e192a0..e6e7fa8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4815,7 +4815,7 @@
      * @see android.net.thread.ThreadNetworkManager
      * @hide
      */
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled")
+    @FlaggedApi(com.android.net.thread.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SystemApi
     public static final String THREAD_NETWORK_SERVICE = "thread_network";
 
@@ -5066,6 +5066,7 @@
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
      *
+     * @removed See {@link android.hardware.biometrics.BiometricPrompt}
      * @see #getSystemService(String)
      * @see android.hardware.fingerprint.FingerprintManager
      */
@@ -6450,6 +6451,19 @@
     @SystemApi
     public static final String WEARABLE_SENSING_SERVICE = "wearable_sensing";
 
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.app.ondeviceintelligence.OnDeviceIntelligenceManager}.
+     *
+     * @see #getSystemService(String)
+     * @see OnDeviceIntelligenceManager
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+    public static final String ON_DEVICE_INTELLIGENCE_SERVICE = "on_device_intelligence";
+
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.health.connect.HealthConnectManager}.
diff --git a/core/java/android/content/pm/ArchivedActivityInfo.java b/core/java/android/content/pm/ArchivedActivityInfo.java
index 166d265..9f65f589 100644
--- a/core/java/android/content/pm/ArchivedActivityInfo.java
+++ b/core/java/android/content/pm/ArchivedActivityInfo.java
@@ -24,6 +24,7 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.util.Slog;
 
 import com.android.internal.util.DataClass;
 
@@ -39,6 +40,7 @@
 @DataClass(genBuilder = false, genConstructor = false, genSetters = true)
 @FlaggedApi(Flags.FLAG_ARCHIVING)
 public final class ArchivedActivityInfo {
+    private static final String TAG = "ArchivedActivityInfo";
     /** The label for the activity. */
     private @NonNull CharSequence mLabel;
     /** The component name of this activity. */
@@ -138,7 +140,8 @@
                 bitmap.getByteCount())) {
             bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
             return baos.toByteArray();
-        } catch (IOException ignored) {
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to compress bitmap", e);
             return null;
         }
     }
@@ -240,10 +243,10 @@
     }
 
     @DataClass.Generated(
-            time = 1705615445673L,
+            time = 1708042076897L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/ArchivedActivityInfo.java",
-            inputSignatures = "private @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static  byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static  android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
+            inputSignatures = "private static final  java.lang.String TAG\nprivate @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.content.ComponentName mComponentName\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mIcon\nprivate @android.annotation.Nullable android.graphics.drawable.Drawable mMonochromeIcon\n @android.annotation.NonNull android.content.pm.ArchivedActivityParcel getParcel()\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable)\npublic static  android.graphics.Bitmap drawableToBitmap(android.graphics.drawable.Drawable,int)\npublic static  byte[] bytesFromBitmap(android.graphics.Bitmap)\nprivate static  android.graphics.drawable.Drawable drawableFromCompressedBitmap(byte[])\nclass ArchivedActivityInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genConstructor=false, genSetters=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2a67353..2a974ed 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3974,7 +3974,7 @@
      * The device is capable of communicating with other devices via
      * <a href="https://www.threadgroup.org">Thread</a> networking protocol.
      */
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled")
+    @FlaggedApi(com.android.net.thread.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
 
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 087a795..55d0bc1 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -115,6 +115,11 @@
     public abstract boolean hasShortcutHostPermission(int launcherUserId,
             @NonNull String callingPackage, int callingPid, int callingUid);
 
+    /**
+     * Returns whether or not Shortcuts are supported on Launcher Home Screen.
+     */
+    public abstract boolean areShortcutsSupportedOnHomeScreen(@UserIdInt int userId);
+
     public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
             int userId);
 
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 6696ba0..5684929 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -156,3 +156,10 @@
     description: "Set power mode during a user switch."
     bug: "325249845"
 }
+
+flag {
+    name: "disable_private_space_items_on_home"
+    namespace: "profile_experiences"
+    description: "Disables adding items belonging to Private Space on Home Screen manually as well as automatically"
+    bug: "287975131"
+}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 23b9d0b..d259e97 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -137,6 +137,8 @@
         private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>();
         private ArrayList<ResourcesLoader> mLoaders = new ArrayList<>();
 
+        private boolean mNoInit = false;
+
         public Builder addApkAssets(ApkAssets apkAssets) {
             mUserApkAssets.add(apkAssets);
             return this;
@@ -147,6 +149,11 @@
             return this;
         }
 
+        public Builder setNoInit() {
+            mNoInit = true;
+            return this;
+        }
+
         public AssetManager build() {
             // Retrieving the system ApkAssets forces their creation as well.
             final ApkAssets[] systemApkAssets = getSystem().getApkAssets();
@@ -188,7 +195,7 @@
             final AssetManager assetManager = new AssetManager(false /*sentinel*/);
             assetManager.mApkAssets = apkAssets;
             AssetManager.nativeSetApkAssets(assetManager.mObject, apkAssets,
-                    false /*invalidateCaches*/);
+                    false /*invalidateCaches*/, mNoInit /*preset*/);
             assetManager.mLoaders = mLoaders.isEmpty() ? null
                     : mLoaders.toArray(new ResourcesLoader[0]);
 
@@ -329,7 +336,7 @@
         synchronized (this) {
             ensureOpenLocked();
             mApkAssets = newApkAssets;
-            nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
+            nativeSetApkAssets(mObject, mApkAssets, invalidateCaches, false);
             if (invalidateCaches) {
                 // Invalidate all caches.
                 invalidateCachesLocked(-1);
@@ -496,7 +503,7 @@
 
             mApkAssets = Arrays.copyOf(mApkAssets, count + 1);
             mApkAssets[count] = assets;
-            nativeSetApkAssets(mObject, mApkAssets, true);
+            nativeSetApkAssets(mObject, mApkAssets, true, false);
             invalidateCachesLocked(-1);
             return count + 1;
         }
@@ -1503,12 +1510,29 @@
             int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp,
             int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode,
             int grammaticalGender, int majorVersion) {
+        setConfigurationInternal(mcc, mnc, defaultLocale, locales, orientation,
+                touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth,
+                screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
+                screenLayout, uiMode, colorMode, grammaticalGender, majorVersion, false);
+    }
+
+    /**
+     * Change the configuration used when retrieving resources, and potentially force a refresh of
+     * the state.  Not for use by applications.
+     * @hide
+     */
+    void setConfigurationInternal(int mcc, int mnc, String defaultLocale, String[] locales,
+            int orientation, int touchscreen, int density, int keyboard, int keyboardHidden,
+            int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp,
+            int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode,
+            int grammaticalGender, int majorVersion, boolean forceRefresh) {
         synchronized (this) {
             ensureValidLocked();
             nativeSetConfiguration(mObject, mcc, mnc, defaultLocale, locales, orientation,
                     touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth,
                     screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
-                    screenLayout, uiMode, colorMode, grammaticalGender, majorVersion);
+                    screenLayout, uiMode, colorMode, grammaticalGender, majorVersion,
+                    forceRefresh);
         }
     }
 
@@ -1593,13 +1617,13 @@
     private static native long nativeCreate();
     private static native void nativeDestroy(long ptr);
     private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
-            boolean invalidateCaches);
+            boolean invalidateCaches, boolean preset);
     private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
             @Nullable String defaultLocale, @NonNull String[] locales, int orientation,
             int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
             int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
             int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
-            int majorVersion);
+            int majorVersion, boolean forceRefresh);
     private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
             long ptr, boolean includeOverlays, boolean includeLoaders);
 
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 5e442b8..079c2c1 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -200,7 +200,7 @@
         mMetrics.setToDefaults();
         mDisplayAdjustments = displayAdjustments;
         mConfiguration.setToDefaults();
-        updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
+        updateConfigurationImpl(config, metrics, displayAdjustments.getCompatibilityInfo(), true);
     }
 
     public DisplayAdjustments getDisplayAdjustments() {
@@ -402,7 +402,12 @@
     }
 
     public void updateConfiguration(Configuration config, DisplayMetrics metrics,
-                                    CompatibilityInfo compat) {
+            CompatibilityInfo compat) {
+        updateConfigurationImpl(config, metrics, compat, false);
+    }
+
+    private void updateConfigurationImpl(Configuration config, DisplayMetrics metrics,
+                                    CompatibilityInfo compat, boolean forceAssetsRefresh) {
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration");
         try {
             synchronized (mAccessLock) {
@@ -528,7 +533,7 @@
                     keyboardHidden = mConfiguration.keyboardHidden;
                 }
 
-                mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
+                mAssets.setConfigurationInternal(mConfiguration.mcc, mConfiguration.mnc,
                         defaultLocale,
                         selectedLocales,
                         mConfiguration.orientation,
@@ -539,7 +544,7 @@
                         mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
                         mConfiguration.screenLayout, mConfiguration.uiMode,
                         mConfiguration.colorMode, mConfiguration.getGrammaticalGender(),
-                        Build.VERSION.RESOURCES_SDK_INT);
+                        Build.VERSION.RESOURCES_SDK_INT, forceAssetsRefresh);
 
                 if (DEBUG_CONFIG) {
                     Slog.i(TAG, "**** Updating config of " + this + ": final config is "
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index d4c58b2..0208fed 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -22,8 +22,9 @@
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT;
-import static android.hardware.biometrics.Flags.FLAG_GET_OP_ID_CRYPTO_OBJECT;
 import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT;
+import static android.hardware.biometrics.Flags.FLAG_GET_OP_ID_CRYPTO_OBJECT;
+import static android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.DrawableRes;
@@ -501,6 +502,28 @@
         }
 
         /**
+         * Remove {@link Builder#setAllowBackgroundAuthentication(boolean)} once
+         * FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE is enabled.
+         *
+         * @param allow If true, allows authentication when the calling package is not in the
+         *              foreground. This is set to false by default.
+         * @param useParentProfileForDeviceCredential If true, uses parent profile for device
+         *                                            credential IME request
+         * @return This builder
+         * @hide
+         */
+        @FlaggedApi(FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE)
+        @TestApi
+        @NonNull
+        @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL})
+        public Builder setAllowBackgroundAuthentication(boolean allow,
+                boolean useParentProfileForDeviceCredential) {
+            mPromptInfo.setAllowBackgroundAuthentication(allow);
+            mPromptInfo.setUseParentProfileForDeviceCredential(useParentProfileForDeviceCredential);
+            return this;
+        }
+
+        /**
          * If set check the Device Policy Manager for disabled biometrics.
          *
          * @param checkDevicePolicyManager
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 2236660..8bb9585 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -55,6 +55,7 @@
     private boolean mIgnoreEnrollmentState;
     private boolean mIsForLegacyFingerprintManager = false;
     private boolean mShowEmergencyCallButton = false;
+    private boolean mUseParentProfileForDeviceCredential = false;
 
     public PromptInfo() {
 
@@ -85,6 +86,7 @@
         mIgnoreEnrollmentState = in.readBoolean();
         mIsForLegacyFingerprintManager = in.readBoolean();
         mShowEmergencyCallButton = in.readBoolean();
+        mUseParentProfileForDeviceCredential = in.readBoolean();
     }
 
     public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -129,6 +131,7 @@
         dest.writeBoolean(mIgnoreEnrollmentState);
         dest.writeBoolean(mIsForLegacyFingerprintManager);
         dest.writeBoolean(mShowEmergencyCallButton);
+        dest.writeBoolean(mUseParentProfileForDeviceCredential);
     }
 
     // LINT.IfChange
@@ -181,6 +184,13 @@
         }
         return false;
     }
+
+    /**
+     * Returns if parent profile needs to be used for device credential.
+     */
+    public boolean shouldUseParentProfileForDeviceCredential() {
+        return mUseParentProfileForDeviceCredential;
+    }
     // LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/BiometricPrompt.java)
 
     // Setters
@@ -281,6 +291,11 @@
         mShowEmergencyCallButton = showEmergencyCallButton;
     }
 
+    public void setUseParentProfileForDeviceCredential(
+            boolean useParentProfileForDeviceCredential) {
+        mUseParentProfileForDeviceCredential = useParentProfileForDeviceCredential;
+    }
+
     // Getters
     @DrawableRes
     public int getLogoRes() {
diff --git a/core/java/android/hardware/devicestate/DeviceState.java b/core/java/android/hardware/devicestate/DeviceState.java
index 8629354..e35e801 100644
--- a/core/java/android/hardware/devicestate/DeviceState.java
+++ b/core/java/android/hardware/devicestate/DeviceState.java
@@ -202,7 +202,7 @@
      * primary display area.
      *
      * Note: This does not necessarily mean that the outer display area is the
-     * @link Display#DEFAULT_DISPLAY}.
+     * {@link Display#DEFAULT_DISPLAY}.
      */
     public static final int PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY = 11;
 
diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java
index 53a9a75..c091062 100644
--- a/core/java/android/hardware/display/BrightnessInfo.java
+++ b/core/java/android/hardware/display/BrightnessInfo.java
@@ -80,6 +80,11 @@
      */
     public static final int BRIGHTNESS_MAX_REASON_POWER_IC = 2;
 
+    /**
+     * Maximum brightness is restricted due to the Wear bedtime mode.
+     */
+    public static final int BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE = 3;
+
     /** Brightness */
     public final float brightness;
 
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 8f0e0c9..eb26a76 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -28,6 +28,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -367,6 +368,8 @@
      * @see #createVirtualDisplay
      * @hide
      */
+    @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+    @TestApi
     public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
 
     /**
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index fe7de83..5a38a34 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -83,7 +83,8 @@
 
 /**
  * A class that coordinates access to the fingerprint hardware.
- * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
+ *
+ * @removed See {@link BiometricPrompt} which shows a system-provided dialog upon starting
  * authentication. In a world where devices may have different types of biometric authentication,
  * it's much more realistic to have a system-provided authentication dialog since the method may
  * vary by vendor/device.
@@ -94,7 +95,6 @@
 @RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
 public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {
     private static final String TAG = "FingerprintManager";
-    private static final boolean DEBUG = true;
     private static final int MSG_ENROLL_RESULT = 100;
     private static final int MSG_ACQUIRED = 101;
     private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -196,6 +196,7 @@
 
     /**
      * Retrieves a test session for FingerprintManager.
+     *
      * @hide
      */
     @TestApi
@@ -254,9 +255,10 @@
     }
 
     /**
-     * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
+     * A wrapper class for the crypto objects supported by FingerprintManager. Currently, the
      * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
-     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
+     *
+     * @removed See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
      */
     @Deprecated
     public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -330,7 +332,8 @@
     /**
      * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
      *     CancellationSignal, int, AuthenticationCallback, Handler)}.
-     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
+     *
+     * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
      */
     @Deprecated
     public static class AuthenticationResult {
@@ -392,7 +395,8 @@
      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
      * fingerprint events.
-     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
+     *
+     * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
      */
     @Deprecated
     public static abstract class AuthenticationCallback
@@ -455,6 +459,7 @@
     /**
      * Callback structure provided for {@link #detectFingerprint(CancellationSignal,
      * FingerprintDetectionCallback, int, Surface)}.
+     *
      * @hide
      */
     public interface FingerprintDetectionCallback {
@@ -608,7 +613,8 @@
      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
      *         facility</a>.
      * @throws IllegalStateException if the crypto primitive is not initialized.
-     * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+     *
+     * @removed See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
      * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
      * BiometricPrompt.CryptoObject, CancellationSignal, Executor,
      * BiometricPrompt.AuthenticationCallback)}
@@ -623,6 +629,7 @@
     /**
      * Per-user version of authenticate.
      * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
+     *
      * @hide
      */
     @Deprecated
@@ -635,6 +642,7 @@
     /**
      * Per-user and per-sensor version of authenticate.
      * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
+     *
      * @hide
      */
     @Deprecated
@@ -651,6 +659,7 @@
 
     /**
      * Version of authenticate with additional options.
+     *
      * @hide
      */
     @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
@@ -698,6 +707,7 @@
     /**
      * Uses the fingerprint hardware to detect for the presence of a finger, without giving details
      * about accept/reject/lockout.
+     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -740,6 +750,7 @@
      * @param callback an object to receive enrollment events
      * @param shouldLogMetrics a flag that indicates if enrollment failure/success metrics
      * should be logged.
+     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -809,6 +820,7 @@
     /**
      * Same as {@link #generateChallenge(int, GenerateChallengeCallback)}, but assumes the first
      * enumerated sensor.
+     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -823,6 +835,7 @@
 
     /**
      * Revokes the specified challenge.
+     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -848,6 +861,7 @@
      * @param sensorId Sensor ID that this operation takes effect for
      * @param userId User ID that this operation takes effect for.
      * @param hardwareAuthToken An opaque token returned by password confirmation.
+     *
      * @hide
      */
     @RequiresPermission(RESET_FINGERPRINT_LOCKOUT)
@@ -885,6 +899,7 @@
 
     /**
      * Removes all fingerprint templates for the given user.
+     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -1004,6 +1019,7 @@
     /**
      * Forwards BiometricStateListener to FingerprintService
      * @param listener new BiometricStateListener being added
+     *
      * @hide
      */
     public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
@@ -1155,7 +1171,8 @@
     }
 
     /**
-     * This is triggered by SideFpsEventHandler
+     * This is triggered by SideFpsEventHandler.
+     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1168,7 +1185,8 @@
      * Determine if there is at least one fingerprint enrolled.
      *
      * @return true if at least one fingerprint is enrolled, false otherwise
-     * @deprecated See {@link BiometricPrompt} and
+     *
+     * @removed See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
      */
     @Deprecated
@@ -1202,7 +1220,8 @@
      * Determine if fingerprint hardware is present and functional.
      *
      * @return true if hardware is present and functional, false otherwise.
-     * @deprecated See {@link BiometricPrompt} and
+     *
+     * @removed See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
      */
     @Deprecated
@@ -1228,6 +1247,7 @@
 
     /**
      * Get statically configured sensor properties.
+     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1246,6 +1266,7 @@
     /**
      * Returns whether the device has a power button fingerprint sensor.
      * @return boolean indicating whether power button is fingerprint sensor
+     *
      * @hide
      */
     public boolean isPowerbuttonFps() {
diff --git a/core/java/android/hardware/input/KeyboardLayoutPreviewDrawable.java b/core/java/android/hardware/input/KeyboardLayoutPreviewDrawable.java
index 1cc910c..e47a48d 100644
--- a/core/java/android/hardware/input/KeyboardLayoutPreviewDrawable.java
+++ b/core/java/android/hardware/input/KeyboardLayoutPreviewDrawable.java
@@ -48,14 +48,13 @@
     private static final int GRAVITY_RIGHT = 0x2;
     private static final int GRAVITY_TOP = 0x4;
     private static final int GRAVITY_BOTTOM = 0x8;
-    private static final int GRAVITY_CENTER =
-            GRAVITY_LEFT | GRAVITY_RIGHT | GRAVITY_TOP | GRAVITY_BOTTOM;
-    private static final int GRAVITY_CENTER_HORIZONTAL = GRAVITY_LEFT | GRAVITY_RIGHT;
+    private static final int TEXT_PADDING_IN_DP = 1;
     private static final int KEY_PADDING_IN_DP = 3;
     private static final int KEYBOARD_PADDING_IN_DP = 10;
     private static final int KEY_RADIUS_IN_DP = 5;
     private static final int KEYBOARD_RADIUS_IN_DP = 10;
-    private static final int GLYPH_TEXT_SIZE_IN_SP = 10;
+    private static final int MIN_GLYPH_TEXT_SIZE_IN_SP = 10;
+    private static final int MAX_GLYPH_TEXT_SIZE_IN_SP = 20;
 
     private final List<KeyDrawable> mKeyDrawables = new ArrayList<>();
 
@@ -107,6 +106,8 @@
         }
         int rowCount = keys.length;
         float keyHeight = (float) (height - rowCount * 2 * keyPadding) / rowCount;
+        // Based on key height calculate the max text size that can fit for typing keys
+        mResourceProvider.calculateBestTextSizeForKey(keyHeight);
         float isoEnterKeyLeft = 0;
         float isoEnterKeyTop = 0;
         float isoEnterWidthUnit = 0;
@@ -136,16 +137,19 @@
                 }
                 if (PhysicalKeyLayout.isSpecialKey(row[j])) {
                     mKeyDrawables.add(new TypingKey(null, keyRect, keyRadius,
+                            mResourceProvider.getTextPadding(),
                             mResourceProvider.getSpecialKeyPaint(),
                             mResourceProvider.getSpecialKeyPaint(),
                             mResourceProvider.getSpecialKeyPaint()));
                 } else if (PhysicalKeyLayout.isKeyPositionUnsure(row[j])) {
                     mKeyDrawables.add(new UnsureTypingKey(row[j].glyph(), keyRect,
-                            keyRadius, mResourceProvider.getTypingKeyPaint(),
+                            keyRadius, mResourceProvider.getTextPadding(),
+                            mResourceProvider.getTypingKeyPaint(),
                             mResourceProvider.getPrimaryGlyphPaint(),
                             mResourceProvider.getSecondaryGlyphPaint()));
                 } else {
                     mKeyDrawables.add(new TypingKey(row[j].glyph(), keyRect, keyRadius,
+                            mResourceProvider.getTextPadding(),
                             mResourceProvider.getTypingKeyPaint(),
                             mResourceProvider.getPrimaryGlyphPaint(),
                             mResourceProvider.getSecondaryGlyphPaint()));
@@ -192,15 +196,18 @@
 
         private final RectF mKeyRect;
         private final float mKeyRadius;
+        private final float mTextPadding;
         private final Paint mKeyPaint;
         private final Paint mBaseTextPaint;
         private final Paint mModifierTextPaint;
         private final List<GlyphDrawable> mGlyphDrawables = new ArrayList<>();
 
         private TypingKey(@Nullable PhysicalKeyLayout.KeyGlyph glyphData, RectF keyRect,
-                float keyRadius, Paint keyPaint, Paint baseTextPaint, Paint modifierTextPaint) {
+                float keyRadius, float textPadding, Paint keyPaint, Paint baseTextPaint,
+                Paint modifierTextPaint) {
             mKeyRect = keyRect;
             mKeyRadius = keyRadius;
+            mTextPadding = textPadding;
             mKeyPaint = keyPaint;
             mBaseTextPaint = baseTextPaint;
             mModifierTextPaint = modifierTextPaint;
@@ -219,20 +226,17 @@
             if (!glyphData.hasBaseText()) {
                 return;
             }
-            boolean isCenter = !glyphData.hasValidAltGrText() && !glyphData.hasValidAltShiftText();
             mGlyphDrawables.add(new GlyphDrawable(glyphData.getBaseText(), new RectF(),
-                    GRAVITY_BOTTOM | (isCenter ? GRAVITY_CENTER_HORIZONTAL : GRAVITY_LEFT),
-                    mBaseTextPaint));
+                    GRAVITY_BOTTOM | GRAVITY_LEFT, mBaseTextPaint));
             if (glyphData.hasValidShiftText()) {
                 mGlyphDrawables.add(new GlyphDrawable(glyphData.getShiftText(), new RectF(),
-                        GRAVITY_TOP | (isCenter ? GRAVITY_CENTER_HORIZONTAL : GRAVITY_LEFT),
-                        mModifierTextPaint));
+                        GRAVITY_TOP | GRAVITY_LEFT, mModifierTextPaint));
             }
             if (glyphData.hasValidAltGrText()) {
                 mGlyphDrawables.add(new GlyphDrawable(glyphData.getAltGrText(), new RectF(),
                         GRAVITY_BOTTOM | GRAVITY_RIGHT, mModifierTextPaint));
             }
-            if (glyphData.hasValidAltShiftText()) {
+            if (glyphData.hasValidAltGrShiftText()) {
                 mGlyphDrawables.add(new GlyphDrawable(glyphData.getAltGrShiftText(), new RectF(),
                         GRAVITY_TOP | GRAVITY_RIGHT, mModifierTextPaint));
             }
@@ -246,15 +250,19 @@
                 float centerY = keyHeight / 2;
                 if ((glyph.gravity & GRAVITY_LEFT) != 0) {
                     centerX -= keyWidth / 4;
+                    centerX += mTextPadding / 2;
                 }
                 if ((glyph.gravity & GRAVITY_RIGHT) != 0) {
                     centerX += keyWidth / 4;
+                    centerX -= mTextPadding / 2;
                 }
                 if ((glyph.gravity & GRAVITY_TOP) != 0) {
                     centerY -= keyHeight / 4;
+                    centerY += mTextPadding / 2;
                 }
                 if ((glyph.gravity & GRAVITY_BOTTOM) != 0) {
                     centerY += keyHeight / 4;
+                    centerY -= mTextPadding / 2;
                 }
                 Rect textBounds = new Rect();
                 glyph.paint.getTextBounds(glyph.text, 0, glyph.text.length(), textBounds);
@@ -285,9 +293,9 @@
     private static class UnsureTypingKey extends TypingKey {
 
         private UnsureTypingKey(@Nullable PhysicalKeyLayout.KeyGlyph glyphData,
-                RectF keyRect, float keyRadius, Paint keyPaint, Paint baseTextPaint,
-                Paint modifierTextPaint) {
-            super(glyphData, keyRect, keyRadius, createGreyedOutPaint(keyPaint),
+                RectF keyRect, float keyRadius, float textPadding, Paint keyPaint,
+                Paint baseTextPaint, Paint modifierTextPaint) {
+            super(glyphData, keyRect, keyRadius, textPadding, createGreyedOutPaint(keyPaint),
                     createGreyedOutPaint(baseTextPaint), createGreyedOutPaint(modifierTextPaint));
         }
     }
@@ -402,8 +410,11 @@
         private final Paint mSecondaryGlyphPaint;
         private final int mKeyPadding;
         private final int mKeyboardPadding;
+        private final float mTextPadding;
         private final float mKeyRadius;
         private final float mBackgroundRadius;
+        private final float mSpToPxMultiplier;
+        private final Paint.FontMetrics mFontMetrics;
 
         private ResourceProvider(Context context) {
             mKeyPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
@@ -414,8 +425,10 @@
                     KEY_RADIUS_IN_DP, context.getResources().getDisplayMetrics());
             mBackgroundRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                     KEYBOARD_RADIUS_IN_DP, context.getResources().getDisplayMetrics());
-            int textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
-                    GLYPH_TEXT_SIZE_IN_SP, context.getResources().getDisplayMetrics());
+            mSpToPxMultiplier = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
+                    context.getResources().getDisplayMetrics());
+            mTextPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    TEXT_PADDING_IN_DP, context.getResources().getDisplayMetrics());
             boolean isDark = (context.getResources().getConfiguration().uiMode
                     & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
             int typingKeyColor = context.getColor(
@@ -430,15 +443,37 @@
             int backgroundColor = context.getColor(
                     isDark ? android.R.color.system_surface_container_dark
                             : android.R.color.system_surface_container_light);
-            mPrimaryGlyphPaint = createTextPaint(primaryGlyphColor, textSize,
+            mPrimaryGlyphPaint = createTextPaint(primaryGlyphColor,
+                    MIN_GLYPH_TEXT_SIZE_IN_SP * mSpToPxMultiplier,
                     Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
-            mSecondaryGlyphPaint = createTextPaint(secondaryGlyphColor, textSize,
+            mSecondaryGlyphPaint = createTextPaint(secondaryGlyphColor,
+                    MIN_GLYPH_TEXT_SIZE_IN_SP * mSpToPxMultiplier,
                     Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL));
+            mFontMetrics = mPrimaryGlyphPaint.getFontMetrics();
             mTypingKeyPaint = createFillPaint(typingKeyColor);
             mSpecialKeyPaint = createFillPaint(specialKeyColor);
             mBackgroundPaint = createFillPaint(backgroundColor);
         }
 
+        private void calculateBestTextSizeForKey(float keyHeight) {
+            int textSize = (int) (mSpToPxMultiplier * MIN_GLYPH_TEXT_SIZE_IN_SP) + 1;
+            while (textSize < mSpToPxMultiplier * MAX_GLYPH_TEXT_SIZE_IN_SP) {
+                updateTextSize(textSize);
+                if (mFontMetrics.bottom - mFontMetrics.top + 3 * mTextPadding > keyHeight / 2) {
+                    textSize--;
+                    break;
+                }
+                textSize++;
+            }
+            updateTextSize(textSize);
+        }
+
+        private void updateTextSize(float textSize) {
+            mPrimaryGlyphPaint.setTextSize(textSize);
+            mSecondaryGlyphPaint.setTextSize(textSize);
+            mPrimaryGlyphPaint.getFontMetrics(mFontMetrics);
+        }
+
         private Paint getBackgroundPaint() {
             return mBackgroundPaint;
         }
@@ -467,6 +502,10 @@
             return mKeyboardPadding;
         }
 
+        private float getTextPadding() {
+            return mTextPadding;
+        }
+
         private float getKeyRadius() {
             return mKeyRadius;
         }
@@ -476,7 +515,8 @@
         }
     }
 
-    private static Paint createTextPaint(@ColorInt int textColor, int textSize, Typeface typeface) {
+    private static Paint createTextPaint(@ColorInt int textColor, float textSize,
+            Typeface typeface) {
         Paint paint = new Paint();
         paint.setColor(textColor);
         paint.setStyle(Paint.Style.FILL);
diff --git a/core/java/android/hardware/input/PhysicalKeyLayout.java b/core/java/android/hardware/input/PhysicalKeyLayout.java
index 844e02f..cff444f 100644
--- a/core/java/android/hardware/input/PhysicalKeyLayout.java
+++ b/core/java/android/hardware/input/PhysicalKeyLayout.java
@@ -336,11 +336,13 @@
             return "";
         }
         int utf8Char = (kcm.get(keyCode, modifierState) & KeyCharacterMap.COMBINING_ACCENT_MASK);
+        if (utf8Char == 0) {
+            return "";
+        }
         if (Character.isValidCodePoint(utf8Char)) {
             return String.valueOf(Character.toChars(utf8Char));
-        } else {
-            return String.valueOf(kcm.getDisplayLabel(keyCode));
         }
+        return "â–¡";
     }
 
     private static LayoutKey getKey(int keyCode, float keyWeight) {
@@ -434,10 +436,11 @@
         }
 
         public boolean hasValidAltGrText() {
-            return !TextUtils.isEmpty(mAltGrText) && !TextUtils.equals(mBaseText, mAltGrText);
+            return !TextUtils.isEmpty(mAltGrText) && !TextUtils.equals(mBaseText, mAltGrText)
+                    && !TextUtils.equals(mShiftText, mAltGrText);
         }
 
-        public boolean hasValidAltShiftText() {
+        public boolean hasValidAltGrShiftText() {
             return !TextUtils.isEmpty(mAltGrShiftText)
                     && !TextUtils.equals(mBaseText, mAltGrShiftText)
                     && !TextUtils.equals(mAltGrText, mAltGrShiftText)
diff --git a/core/java/android/hardware/input/VirtualKeyboard.java b/core/java/android/hardware/input/VirtualKeyboard.java
index 6eb2ae3..6a7d195 100644
--- a/core/java/android/hardware/input/VirtualKeyboard.java
+++ b/core/java/android/hardware/input/VirtualKeyboard.java
@@ -18,7 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.companion.virtual.IVirtualDevice;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -66,4 +68,15 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * @return The id of the {@link android.view.InputDevice} corresponding to this keyboard.
+     * @hide
+     */
+    @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+    @TestApi
+    @Override
+    public int getInputDeviceId() {
+        return super.getInputDeviceId();
+    }
 }
diff --git a/core/java/android/net/thread/flags.aconfig b/core/java/android/net/thread/flags.aconfig
index 6e72f8e..ff762d7 100644
--- a/core/java/android/net/thread/flags.aconfig
+++ b/core/java/android/net/thread/flags.aconfig
@@ -1,8 +1,18 @@
 package: "com.android.net.thread.flags"
 
+# This file contains aconfig flags used from platform code
+# Flags used for module APIs must be in aconfig files under each modules
+
 flag {
     name: "thread_user_restriction_enabled"
     namespace: "thread_network"
     description: "Controls whether user restriction on thread networks is enabled"
     bug: "307679182"
 }
+
+flag {
+    name: "thread_enabled_platform"
+    namespace: "thread_network"
+    description: "Controls whether the Android Thread feature is enabled"
+    bug: "301473012"
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2b30a2b..7873a76 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1920,7 +1920,7 @@
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
-    @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+    @FlaggedApi(com.android.net.thread.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED)
     public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
 
     /**
diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
new file mode 100644
index 0000000..bbb4bc6
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.ondeviceintelligence;
+
+import android.os.PersistableBundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ICancellationSignal;
+import android.os.RemoteCallback;
+import android.app.ondeviceintelligence.IDownloadCallback;
+import android.app.ondeviceintelligence.Feature;
+import android.app.ondeviceintelligence.IFeatureCallback;
+import android.app.ondeviceintelligence.IListFeaturesCallback;
+import android.app.ondeviceintelligence.IFeatureDetailsCallback;
+import com.android.internal.infra.AndroidFuture;
+
+
+/**
+ * Interface for a concrete implementation to provide on device intelligence services.
+ *
+ * @hide
+ */
+oneway interface IOnDeviceIntelligenceService {
+    void getVersion(in RemoteCallback remoteCallback);
+    void getFeature(in int featureId, in IFeatureCallback featureCallback);
+    void listFeatures(in IListFeaturesCallback listFeaturesCallback);
+    void getFeatureDetails(in Feature feature, in IFeatureDetailsCallback featureDetailsCallback);
+    void getReadOnlyFileDescriptor(in String fileName, in AndroidFuture<ParcelFileDescriptor> future);
+    void getReadOnlyFeatureFileDescriptorMap(in Feature feature, in RemoteCallback remoteCallback);
+    void requestFeatureDownload(in Feature feature, in ICancellationSignal cancellationSignal, in IDownloadCallback downloadCallback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl
new file mode 100644
index 0000000..08eb927
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.IStreamingResponseCallback;
+import android.app.ondeviceintelligence.IResponseCallback;
+import android.app.ondeviceintelligence.ITokenCountCallback;
+import android.app.ondeviceintelligence.IProcessingSignal;
+import android.app.ondeviceintelligence.Content;
+import android.app.ondeviceintelligence.Feature;
+import android.os.ICancellationSignal;
+import android.service.ondeviceintelligence.IRemoteStorageService;
+
+
+/**
+ * Interface for a concrete implementation to provide on device trusted inference.
+ *
+ * @hide
+ */
+oneway interface IOnDeviceTrustedInferenceService {
+    void registerRemoteStorageService(in IRemoteStorageService storageService);
+    void requestTokenCount(in Feature feature, in Content request, in ICancellationSignal cancellationSignal,
+                            in ITokenCountCallback tokenCountCallback);
+    void processRequest(in Feature feature, in Content request, in int requestType,
+                        in ICancellationSignal cancellationSignal, in IProcessingSignal processingSignal,
+                        in IResponseCallback callback);
+    void processRequestStreaming(in Feature feature, in Content request, in int requestType,
+                                in ICancellationSignal cancellationSignal, in IProcessingSignal processingSignal,
+                                in IStreamingResponseCallback callback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/ondeviceintelligence/IRemoteStorageService.aidl b/core/java/android/service/ondeviceintelligence/IRemoteStorageService.aidl
new file mode 100644
index 0000000..a6f49e1
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/IRemoteStorageService.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.ondeviceintelligence;
+
+import android.app.ondeviceintelligence.Feature;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallback;
+
+import com.android.internal.infra.AndroidFuture;
+
+/**
+ * Interface for a concrete implementation to provide access to storage read access
+ * for the isolated process.
+ *
+ * @hide
+ */
+oneway interface IRemoteStorageService {
+    void getReadOnlyFileDescriptor(in String filePath, in AndroidFuture<ParcelFileDescriptor> future);
+    void getReadOnlyFeatureFileDescriptorMap(in Feature feature, in RemoteCallback remoteCallback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
new file mode 100644
index 0000000..0cba1d3
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.ondeviceintelligence.DownloadCallback;
+import android.app.ondeviceintelligence.Feature;
+import android.app.ondeviceintelligence.FeatureDetails;
+import android.app.ondeviceintelligence.IDownloadCallback;
+import android.app.ondeviceintelligence.IFeatureCallback;
+import android.app.ondeviceintelligence.IFeatureDetailsCallback;
+import android.app.ondeviceintelligence.IListFeaturesCallback;
+import android.app.ondeviceintelligence.OnDeviceIntelligenceManager;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.OutcomeReceiver;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Abstract base class for performing setup for on-device inference and providing file access to
+ * the isolated counter part {@link OnDeviceTrustedInferenceService}.
+ *
+ * <p> A service that provides configuration and model files relevant to performing inference on
+ * device. The system's default OnDeviceIntelligenceService implementation is configured in
+ * {@code config_defaultOnDeviceIntelligenceService}. If this config has no value, a stub is
+ * returned.
+ *
+ * <pre>
+ * {@literal
+ * <service android:name=".SampleOnDeviceIntelligenceService"
+ *          android:permission="android.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE">
+ * </service>}
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public abstract class OnDeviceIntelligenceService extends Service {
+    private static final String TAG = OnDeviceIntelligenceService.class.getSimpleName();
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service. To be supported, the
+     * service must also require the
+     * {@link android.Manifest.permission#BIND_ON_DEVICE_INTELLIGENCE_SERVICE}
+     * permission so that other applications can not abuse it.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.service.ondeviceintelligence.OnDeviceIntelligenceService";
+
+    /**
+     * @hide
+     */
+    @Nullable
+    @Override
+    public final IBinder onBind(@NonNull Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return new IOnDeviceIntelligenceService.Stub() {
+                /** {@inheritDoc} */
+                @Override
+                public void getVersion(RemoteCallback remoteCallback) {
+                    Objects.requireNonNull(remoteCallback);
+                    OnDeviceIntelligenceService.this.onGetVersion(l -> {
+                        Bundle b = new Bundle();
+                        b.putLong(OnDeviceIntelligenceManager.API_VERSION_BUNDLE_KEY, l);
+                        remoteCallback.sendResult(b);
+                    });
+                }
+
+                @Override
+                public void listFeatures(IListFeaturesCallback listFeaturesCallback) {
+                    Objects.requireNonNull(listFeaturesCallback);
+                    OnDeviceIntelligenceService.this.onListFeatures(
+                            wrapListFeaturesCallback(listFeaturesCallback));
+                }
+
+                @Override
+                public void getFeature(int id, IFeatureCallback featureCallback) {
+                    Objects.requireNonNull(featureCallback);
+                    OnDeviceIntelligenceService.this.onGetFeature(id,
+                            wrapFeatureCallback(featureCallback));
+                }
+
+
+                @Override
+                public void getFeatureDetails(Feature feature,
+                        IFeatureDetailsCallback featureDetailsCallback) {
+                    Objects.requireNonNull(feature);
+                    Objects.requireNonNull(featureDetailsCallback);
+
+                    OnDeviceIntelligenceService.this.onGetFeatureDetails(feature,
+                            wrapFeatureDetailsCallback(featureDetailsCallback));
+                }
+
+                @Override
+                public void requestFeatureDownload(Feature feature,
+                        ICancellationSignal cancellationSignal,
+                        IDownloadCallback downloadCallback) {
+                    Objects.requireNonNull(feature);
+                    Objects.requireNonNull(downloadCallback);
+
+                    OnDeviceIntelligenceService.this.onDownloadFeature(feature,
+                            CancellationSignal.fromTransport(cancellationSignal),
+                            wrapDownloadCallback(downloadCallback));
+                }
+
+                @Override
+                public void getReadOnlyFileDescriptor(String fileName,
+                        AndroidFuture<ParcelFileDescriptor> future) {
+                    Objects.requireNonNull(fileName);
+                    Objects.requireNonNull(future);
+
+                    OnDeviceIntelligenceService.this.onGetReadOnlyFileDescriptor(fileName,
+                            future);
+                }
+
+                @Override
+                public void getReadOnlyFeatureFileDescriptorMap(
+                        Feature feature, RemoteCallback remoteCallback) {
+                    Objects.requireNonNull(feature);
+                    Objects.requireNonNull(remoteCallback);
+
+                    OnDeviceIntelligenceService.this.onGetReadOnlyFeatureFileDescriptorMap(
+                            feature, parcelFileDescriptorMap -> {
+                                Bundle bundle = new Bundle();
+                                parcelFileDescriptorMap.forEach(bundle::putParcelable);
+                                remoteCallback.sendResult(bundle);
+                            });
+                }
+            };
+        }
+        Slog.w(TAG, "Incorrect service interface, returning null.");
+        return null;
+    }
+
+    private OutcomeReceiver<Feature,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> wrapFeatureCallback(
+            IFeatureCallback featureCallback) {
+        return new OutcomeReceiver<>() {
+            @Override
+            public void onResult(@NonNull Feature feature) {
+                try {
+                    featureCallback.onSuccess(feature);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending feature: " + e);
+                }
+            }
+
+            @Override
+            public void onError(
+                    @NonNull OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException exception) {
+                try {
+                    featureCallback.onFailure(exception.getErrorCode(), exception.getMessage(),
+                            exception.getErrorParams());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending download feature: " + e);
+                }
+            }
+        };
+
+    }
+
+    private OutcomeReceiver<List<Feature>,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> wrapListFeaturesCallback(
+            IListFeaturesCallback listFeaturesCallback) {
+        return new OutcomeReceiver<>() {
+            @Override
+            public void onResult(@NonNull List<Feature> features) {
+                try {
+                    listFeaturesCallback.onSuccess(features);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending feature: " + e);
+                }
+            }
+
+            @Override
+            public void onError(
+                    @NonNull OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException exception) {
+                try {
+                    listFeaturesCallback.onFailure(exception.getErrorCode(), exception.getMessage(),
+                            exception.getErrorParams());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending download feature: " + e);
+                }
+            }
+        };
+    }
+
+    private OutcomeReceiver<FeatureDetails,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> wrapFeatureDetailsCallback(
+            IFeatureDetailsCallback featureStatusCallback) {
+        return new OutcomeReceiver<>() {
+            @Override
+            public void onResult(FeatureDetails result) {
+                try {
+                    featureStatusCallback.onSuccess(result);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending feature status: " + e);
+                }
+            }
+
+            @Override
+            public void onError(
+                    @NonNull OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException exception) {
+                try {
+                    featureStatusCallback.onFailure(exception.getErrorCode(),
+                            exception.getMessage(), exception.getErrorParams());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending feature status: " + e);
+                }
+            }
+        };
+    }
+
+
+    private DownloadCallback wrapDownloadCallback(IDownloadCallback downloadCallback) {
+        return new DownloadCallback() {
+            @Override
+            public void onDownloadStarted(long bytesToDownload) {
+                try {
+                    downloadCallback.onDownloadStarted(bytesToDownload);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending download status: " + e);
+                }
+            }
+
+            @Override
+            public void onDownloadFailed(int failureStatus,
+                    String errorMessage, @NonNull PersistableBundle errorParams) {
+                try {
+                    downloadCallback.onDownloadFailed(failureStatus, errorMessage, errorParams);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending download status: " + e);
+                }
+            }
+
+            @Override
+            public void onDownloadProgress(long totalBytesDownloaded) {
+                try {
+                    downloadCallback.onDownloadProgress(totalBytesDownloaded);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending download status: " + e);
+                }
+            }
+
+            @Override
+            public void onDownloadCompleted(@NonNull PersistableBundle persistableBundle) {
+                try {
+                    downloadCallback.onDownloadCompleted(persistableBundle);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending download status: " + e);
+                }
+            }
+        };
+    }
+
+    private void onGetReadOnlyFileDescriptor(@NonNull String fileName,
+            @NonNull AndroidFuture<ParcelFileDescriptor> future) {
+        Slog.v(TAG, "onGetReadOnlyFileDescriptor " + fileName);
+        Binder.withCleanCallingIdentity(() -> {
+            Slog.v(TAG,
+                    "onGetReadOnlyFileDescriptor: " + fileName + " under internal app storage.");
+            File f = new File(getBaseContext().getFilesDir(), fileName);
+            ParcelFileDescriptor pfd = null;
+            try {
+                pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
+                Slog.d(TAG, "Successfully opened a file with ParcelFileDescriptor.");
+            } catch (FileNotFoundException e) {
+                Slog.e(TAG, "Cannot open file. No ParcelFileDescriptor returned.");
+            } finally {
+                future.complete(pfd);
+            }
+        });
+    }
+
+    /**
+     * Provide implementation for a scenario when caller wants to get all feature related
+     * file-descriptors that might be required for processing a request for the corresponding the
+     * feature.
+     *
+     * @param feature                   the feature for which files need to be opened.
+     * @param fileDescriptorMapConsumer callback to be populated with a map of file-path and
+     *                                  corresponding ParcelDescriptor to be used in a remote
+     *                                  service.
+     */
+    public abstract void onGetReadOnlyFeatureFileDescriptorMap(
+            @NonNull Feature feature,
+            @NonNull Consumer<Map<String, ParcelFileDescriptor>> fileDescriptorMapConsumer);
+
+    /**
+     * Request download for feature that is requested and listen to download progress updates. If
+     * the download completes successfully, success callback should be populated.
+     *
+     * @param feature            the feature for which files need to be downlaoded.
+     *                           process.
+     * @param cancellationSignal signal to attach a listener to, and receive cancellation signals
+     *                           from thw client.
+     * @param downloadCallback   callback to populate download updates for clients to listen on..
+     */
+    public abstract void onDownloadFeature(
+            @NonNull Feature feature,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull DownloadCallback downloadCallback);
+
+    /**
+     * Provide feature details for the passed in feature. Usually the client and remote
+     * implementation use the {@link Feature#getFeatureParams()} as a hint to communicate what
+     * details the client is looking for.
+     *
+     * @param feature               the feature for which status needs to be known.
+     * @param featureStatusCallback callback to populate the resulting feature status.
+     */
+    public abstract void onGetFeatureDetails(@NonNull Feature feature,
+            @NonNull OutcomeReceiver<FeatureDetails,
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> featureStatusCallback);
+
+
+    /**
+     * Get feature using the provided identifier to the remote implementation.
+     *
+     * @param featureCallback callback to populate the features list.
+     */
+    public abstract void onGetFeature(int featureId,
+            @NonNull OutcomeReceiver<Feature,
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> featureCallback);
+
+    /**
+     * List all features which are available in the remote implementation. The implementation might
+     * choose to provide only a certain list of features based on the caller.
+     *
+     * @param listFeaturesCallback callback to populate the features list.
+     */
+    public abstract void onListFeatures(@NonNull OutcomeReceiver<List<Feature>,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> listFeaturesCallback);
+
+    /**
+     * Provides a long value representing the version of the remote implementation processing
+     * requests.
+     *
+     * @param versionConsumer consumer to populate the version.
+     */
+    public abstract void onGetVersion(@NonNull LongConsumer versionConsumer);
+}
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java
new file mode 100644
index 0000000..96982e3
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.ondeviceintelligence;
+
+import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.ondeviceintelligence.Content;
+import android.app.ondeviceintelligence.Feature;
+import android.app.ondeviceintelligence.IProcessingSignal;
+import android.app.ondeviceintelligence.IResponseCallback;
+import android.app.ondeviceintelligence.IStreamingResponseCallback;
+import android.app.ondeviceintelligence.ITokenCountCallback;
+import android.app.ondeviceintelligence.OnDeviceIntelligenceManager;
+import android.app.ondeviceintelligence.ProcessingSignal;
+import android.app.ondeviceintelligence.StreamingResponseReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.OutcomeReceiver;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Abstract base class for performing inference in a isolated process. This service exposes its
+ * methods via {@link android.app.ondeviceintelligence.OnDeviceIntelligenceManager}.
+ *
+ * <p> A service that provides methods to perform on-device inference both in streaming and
+ * non-streaming fashion. Also, provides a way to register a storage service that will be used to
+ * read-only access files from the {@link OnDeviceIntelligenceService} counterpart. </p>
+ *
+ * <pre>
+ * {@literal
+ * <service android:name=".SampleTrustedInferenceService"
+ *          android:permission="android.permission.BIND_ONDEVICE_TRUSTED_INFERENCE_SERVICE"
+ *          android:isolatedProcess="true">
+ * </service>}
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_ENABLE_ON_DEVICE_INTELLIGENCE)
+public abstract class OnDeviceTrustedInferenceService extends Service {
+    private static final String TAG = OnDeviceTrustedInferenceService.class.getSimpleName();
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service. To be supported, the
+     * service must also require the
+     * {@link android.Manifest.permission#BIND_ON_DEVICE_TRUSTED_INFERENCE_SERVICE}
+     * permission so that other applications can not abuse it.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.service.ondeviceintelligence.OnDeviceTrustedInferenceService";
+
+    private IRemoteStorageService mRemoteStorageService;
+
+    /**
+     * @hide
+     */
+    @Nullable
+    @Override
+    public final IBinder onBind(@NonNull Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return new IOnDeviceTrustedInferenceService.Stub() {
+                @Override
+                public void registerRemoteStorageService(IRemoteStorageService storageService) {
+                    Objects.requireNonNull(storageService);
+                    mRemoteStorageService = storageService;
+                }
+
+                @Override
+                public void requestTokenCount(Feature feature, Content request,
+                        ICancellationSignal cancellationSignal,
+                        ITokenCountCallback tokenCountCallback) {
+                    Objects.requireNonNull(feature);
+                    Objects.requireNonNull(tokenCountCallback);
+                    OnDeviceTrustedInferenceService.this.onCountTokens(feature,
+                            request,
+                            CancellationSignal.fromTransport(cancellationSignal),
+                            wrapTokenCountCallback(tokenCountCallback));
+                }
+
+                @Override
+                public void processRequestStreaming(Feature feature, Content request,
+                        int requestType, ICancellationSignal cancellationSignal,
+                        IProcessingSignal processingSignal,
+                        IStreamingResponseCallback callback) {
+                    Objects.requireNonNull(feature);
+                    Objects.requireNonNull(request);
+                    Objects.requireNonNull(callback);
+
+                    OnDeviceTrustedInferenceService.this.onProcessRequestStreaming(feature,
+                            request,
+                            requestType,
+                            CancellationSignal.fromTransport(cancellationSignal),
+                            ProcessingSignal.fromTransport(processingSignal),
+                            wrapStreamingResponseCallback(callback)
+                    );
+                }
+
+                @Override
+                public void processRequest(Feature feature, Content request,
+                        int requestType, ICancellationSignal cancellationSignal,
+                        IProcessingSignal processingSignal,
+                        IResponseCallback callback) {
+                    Objects.requireNonNull(feature);
+                    Objects.requireNonNull(request);
+                    Objects.requireNonNull(callback);
+
+
+                    OnDeviceTrustedInferenceService.this.onProcessRequest(feature, request,
+                            requestType, CancellationSignal.fromTransport(cancellationSignal),
+                            ProcessingSignal.fromTransport(processingSignal),
+                            wrapResponseCallback(callback)
+                    );
+                }
+            };
+        }
+        Slog.w(TAG, "Incorrect service interface, returning null.");
+        return null;
+    }
+
+    /**
+     * Invoked when caller  wants to obtain a count of number of tokens present in the passed in
+     * Request associated with the provided feature.
+     * The expectation from the implementation is that when processing is complete, it
+     * should provide the token count in the {@link OutcomeReceiver#onResult}.
+     *
+     * @param feature            feature which is associated with the request.
+     * @param request            request that requires processing.
+     * @param cancellationSignal Cancellation Signal to receive cancellation events from client and
+     *                           configure a listener to.
+     * @param callback           callback to populate failure and full response for the provided
+     *                           request.
+     */
+    @NonNull
+    public abstract void onCountTokens(
+            @NonNull Feature feature,
+            @NonNull Content request,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull OutcomeReceiver<Long,
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> callback);
+
+    /**
+     * Invoked when caller provides a request for a particular feature to be processed in a
+     * streaming manner. The expectation from the implementation is that when processing the
+     * request,
+     * it periodically populates the {@link StreamingResponseReceiver#onNewContent} to continuously
+     * provide partial Content results for the caller to utilize. Optionally the implementation can
+     * provide the complete response in the {@link StreamingResponseReceiver#onResult} upon
+     * processing completion.
+     *
+     * @param feature            feature which is associated with the request.
+     * @param request            request that requires processing.
+     * @param requestType        identifier representing the type of request.
+     * @param cancellationSignal Cancellation Signal to receive cancellation events from client and
+     *                           configure a listener to.
+     * @param processingSignal   Signal to receive custom action instructions from client.
+     * @param callback           callback to populate the partial responses, failure and optionally
+     *                           full response for the provided request.
+     */
+    @NonNull
+    public abstract void onProcessRequestStreaming(
+            @NonNull Feature feature,
+            @NonNull Content request,
+            @OnDeviceIntelligenceManager.RequestType int requestType,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable ProcessingSignal processingSignal,
+            @NonNull StreamingResponseReceiver<Content, Content,
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> callback);
+
+    /**
+     * Invoked when caller provides a request for a particular feature to be processed in one shot
+     * completely.
+     * The expectation from the implementation is that when processing the request is complete, it
+     * should
+     * provide the complete response in the {@link OutcomeReceiver#onResult}.
+     *
+     * @param feature            feature which is associated with the request.
+     * @param request            request that requires processing.
+     * @param requestType        identifier representing the type of request.
+     * @param cancellationSignal Cancellation Signal to receive cancellation events from client and
+     *                           configure a listener to.
+     * @param processingSignal   Signal to receive custom action instructions from client.
+     * @param callback           callback to populate failure and full response for the provided
+     *                           request.
+     */
+    @NonNull
+    public abstract void onProcessRequest(
+            @NonNull Feature feature,
+            @NonNull Content request,
+            @OnDeviceIntelligenceManager.RequestType int requestType,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable ProcessingSignal processingSignal,
+            @NonNull OutcomeReceiver<Content,
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> callback);
+
+    /**
+     * Overrides {@link Context#openFileInput} to read files with the given file names under the
+     * internal app storage of the {@link OnDeviceIntelligenceService}, i.e., only files stored in
+     * {@link Context#getFilesDir()} can be opened.
+     */
+    @Override
+    public final FileInputStream openFileInput(@NonNull String filename) throws
+            FileNotFoundException {
+        try {
+            AndroidFuture<ParcelFileDescriptor> future = new AndroidFuture<>();
+            mRemoteStorageService.getReadOnlyFileDescriptor(filename, future);
+            ParcelFileDescriptor pfd = future.get();
+            return new FileInputStream(pfd.getFileDescriptor());
+        } catch (RemoteException | ExecutionException | InterruptedException e) {
+            Log.w(TAG, "Cannot open file due to remote service failure");
+            throw new FileNotFoundException(e.getMessage());
+        }
+    }
+
+    /**
+     * Provides read-only access to the internal app storage via the
+     * {@link OnDeviceIntelligenceService}. This is an asynchronous implementation for
+     * {@link #openFileInput(String)}.
+     *
+     * @param fileName       File name relative to the {@link Context#getFilesDir()}.
+     * @param resultConsumer Consumer to populate the corresponding file stream in.
+     */
+    public final void openFileInputAsync(@NonNull String fileName,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<FileInputStream> resultConsumer) throws FileNotFoundException {
+        AndroidFuture<ParcelFileDescriptor> future = new AndroidFuture<>();
+        try {
+            mRemoteStorageService.getReadOnlyFileDescriptor(fileName, future);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot open file due to remote service failure");
+            throw new FileNotFoundException(e.getMessage());
+        }
+        future.whenCompleteAsync((pfd, err) -> {
+            if (err != null) {
+                Log.e(TAG, "Failure when reading file: " + fileName + err);
+                executor.execute(() -> resultConsumer.accept(null));
+            } else {
+                executor.execute(
+                        () -> resultConsumer.accept(new FileInputStream(pfd.getFileDescriptor())));
+            }
+        }, executor);
+    }
+
+    /**
+     * Provides access to all file streams required for feature via the
+     * {@link OnDeviceIntelligenceService}.
+     *
+     * @param feature        Feature for which the associated files should be fetched.
+     * @param executor       Executor to run the consumer callback on.
+     * @param resultConsumer Consumer to receive a map of filePath to the corresponding file input
+     *                       stream.
+     */
+    public final void fetchFeatureFileInputStreamMap(@NonNull Feature feature,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Map<String, FileInputStream>> resultConsumer) {
+        try {
+            mRemoteStorageService.getReadOnlyFeatureFileDescriptorMap(feature,
+                    wrapResultReceiverAsReadOnly(resultConsumer, executor));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private RemoteCallback wrapResultReceiverAsReadOnly(
+            @NonNull Consumer<Map<String, FileInputStream>> resultConsumer,
+            @NonNull Executor executor) {
+        return new RemoteCallback(result -> {
+            if (result == null) {
+                executor.execute(() -> resultConsumer.accept(new HashMap<>()));
+            } else {
+                Map<String, FileInputStream> bundleMap = new HashMap<>();
+                result.keySet().forEach(key -> {
+                    ParcelFileDescriptor pfd = result.getParcelable(key,
+                            ParcelFileDescriptor.class);
+                    if (pfd != null) {
+                        bundleMap.put(key, new FileInputStream(pfd.getFileDescriptor()));
+                    }
+                });
+                executor.execute(() -> resultConsumer.accept(bundleMap));
+            }
+        });
+    }
+
+    private OutcomeReceiver<Content,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> wrapResponseCallback(
+            IResponseCallback callback) {
+        return new OutcomeReceiver<>() {
+            @Override
+            public void onResult(@androidx.annotation.NonNull Content response) {
+                try {
+                    callback.onSuccess(response);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+                }
+            }
+
+            @Override
+            public void onError(
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException exception) {
+                try {
+                    callback.onFailure(exception.getErrorCode(), exception.getMessage(),
+                            exception.getErrorParams());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+                }
+            }
+        };
+    }
+
+    private StreamingResponseReceiver<Content, Content,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> wrapStreamingResponseCallback(
+            IStreamingResponseCallback callback) {
+        return new StreamingResponseReceiver<>() {
+            @Override
+            public void onNewContent(@androidx.annotation.NonNull Content content) {
+                try {
+                    callback.onNewContent(content);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+                }
+            }
+
+            @Override
+            public void onResult(@androidx.annotation.NonNull Content response) {
+                try {
+                    callback.onSuccess(response);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+                }
+            }
+
+            @Override
+            public void onError(
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException exception) {
+                try {
+                    callback.onFailure(exception.getErrorCode(), exception.getMessage(),
+                            exception.getErrorParams());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+                }
+            }
+        };
+    }
+
+    private OutcomeReceiver<Long,
+            OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> wrapTokenCountCallback(
+            ITokenCountCallback tokenCountCallback) {
+        return new OutcomeReceiver<>() {
+            @Override
+            public void onResult(Long tokenCount) {
+                try {
+                    tokenCountCallback.onSuccess(tokenCount);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+                }
+            }
+
+            @Override
+            public void onError(
+                    OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException exception) {
+                try {
+                    tokenCountCallback.onFailure(exception.getErrorCode(), exception.getMessage(),
+                            exception.getErrorParams());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending failure: " + e);
+                }
+            }
+        };
+    }
+}
diff --git a/core/java/android/service/voice/VisualQueryDetectedResult.java b/core/java/android/service/voice/VisualQueryDetectedResult.java
index 322148a..3b61794 100644
--- a/core/java/android/service/voice/VisualQueryDetectedResult.java
+++ b/core/java/android/service/voice/VisualQueryDetectedResult.java
@@ -68,6 +68,22 @@
         return 15;
     }
 
+    /**
+     * Detected signal representing the arbitrary data that will make accessibility detections work.
+     *
+     * This field should only be set if the device setting for allowing accessibility data is on
+     * based on the result of {@link VisualQueryDetector#isAccessibilityDetectionEnabled()}. If the
+     * enable bit return by the method is {@code false}, it would suggest a failure to egress the
+     * {@link VisualQueryDetectedResult} object with this field set. The system server will prevent
+     * egress and invoke
+     * {@link VisualQueryDetector.Callback#onFailure(VisualQueryDetectionServiceFailure)}.
+     */
+    @Nullable
+    private final byte[] mAccessibilityDetectionData;
+    private static byte[] defaultAccessibilityDetectionData() {
+        return null;
+    }
+
     private void onConstructed() {
         Preconditions.checkArgumentInRange(mSpeakerId, 0, getMaxSpeakerId(), "speakerId");
     }
@@ -78,7 +94,10 @@
      * @hide
      */
     public Builder buildUpon() {
-        return new Builder().setPartialQuery(mPartialQuery).setSpeakerId(mSpeakerId);
+        return new Builder()
+                .setPartialQuery(mPartialQuery)
+                .setSpeakerId(mSpeakerId)
+                .setAccessibilityDetectionData(mAccessibilityDetectionData);
     }
 
 
@@ -98,11 +117,13 @@
     @DataClass.Generated.Member
     /* package-private */ VisualQueryDetectedResult(
             @NonNull String partialQuery,
-            int speakerId) {
+            int speakerId,
+            @Nullable byte[] accessibilityDetectionData) {
         this.mPartialQuery = partialQuery;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPartialQuery);
         this.mSpeakerId = speakerId;
+        this.mAccessibilityDetectionData = accessibilityDetectionData;
 
         onConstructed();
     }
@@ -125,6 +146,16 @@
         return mSpeakerId;
     }
 
+    /**
+     * Detected signal representing the data for allowing accessibility feature. This field can
+     * only be set when the secure device settings is set to true by either settings page UI or
+     * {@link VisualQueryDetector@setAccessibilityDetectionEnabled(boolean)}
+     */
+    @DataClass.Generated.Member
+    public @Nullable byte[] getAccessibilityDetectionData() {
+        return mAccessibilityDetectionData;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -133,7 +164,8 @@
 
         return "VisualQueryDetectedResult { " +
                 "partialQuery = " + mPartialQuery + ", " +
-                "speakerId = " + mSpeakerId +
+                "speakerId = " + mSpeakerId + ", " +
+                "accessibilityDetectionData = " + java.util.Arrays.toString(mAccessibilityDetectionData) +
         " }";
     }
 
@@ -151,7 +183,8 @@
         //noinspection PointlessBooleanExpression
         return true
                 && Objects.equals(mPartialQuery, that.mPartialQuery)
-                && mSpeakerId == that.mSpeakerId;
+                && mSpeakerId == that.mSpeakerId
+                && java.util.Arrays.equals(mAccessibilityDetectionData, that.mAccessibilityDetectionData);
     }
 
     @Override
@@ -163,6 +196,7 @@
         int _hash = 1;
         _hash = 31 * _hash + Objects.hashCode(mPartialQuery);
         _hash = 31 * _hash + mSpeakerId;
+        _hash = 31 * _hash + java.util.Arrays.hashCode(mAccessibilityDetectionData);
         return _hash;
     }
 
@@ -174,6 +208,7 @@
 
         dest.writeString(mPartialQuery);
         dest.writeInt(mSpeakerId);
+        dest.writeByteArray(mAccessibilityDetectionData);
     }
 
     @Override
@@ -189,11 +224,13 @@
 
         String partialQuery = in.readString();
         int speakerId = in.readInt();
+        byte[] accessibilityDetectionData = in.createByteArray();
 
         this.mPartialQuery = partialQuery;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPartialQuery);
         this.mSpeakerId = speakerId;
+        this.mAccessibilityDetectionData = accessibilityDetectionData;
 
         onConstructed();
     }
@@ -221,6 +258,7 @@
 
         private @NonNull String mPartialQuery;
         private int mSpeakerId;
+        private @Nullable byte[] mAccessibilityDetectionData;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -251,10 +289,23 @@
             return this;
         }
 
+        /**
+         * Detected signal representing the data for allowing accessibility feature. This field can
+         * only be set when the secure device settings is set to true by either settings page UI or
+         * {@link VisualQueryDetector@setAccessibilityDetectionEnabled(boolean)}
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setAccessibilityDetectionData(@NonNull byte... value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mAccessibilityDetectionData = value;
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull VisualQueryDetectedResult build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x4; // Mark builder used
+            mBuilderFieldsSet |= 0x8; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mPartialQuery = defaultPartialQuery();
@@ -262,14 +313,18 @@
             if ((mBuilderFieldsSet & 0x2) == 0) {
                 mSpeakerId = defaultSpeakerId();
             }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mAccessibilityDetectionData = defaultAccessibilityDetectionData();
+            }
             VisualQueryDetectedResult o = new VisualQueryDetectedResult(
                     mPartialQuery,
-                    mSpeakerId);
+                    mSpeakerId,
+                    mAccessibilityDetectionData);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x4) != 0) {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -277,10 +332,10 @@
     }
 
     @DataClass.Generated(
-            time = 1704949386772L,
+            time = 1707429290528L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/service/voice/VisualQueryDetectedResult.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPartialQuery\nprivate final  int mSpeakerId\nprivate static  java.lang.String defaultPartialQuery()\nprivate static  int defaultSpeakerId()\npublic static  int getMaxSpeakerId()\nprivate  void onConstructed()\npublic  android.service.voice.VisualQueryDetectedResult.Builder buildUpon()\nclass VisualQueryDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPartialQuery\nprivate final  int mSpeakerId\nprivate final @android.annotation.Nullable byte[] mAccessibilityDetectionData\nprivate static  java.lang.String defaultPartialQuery()\nprivate static  int defaultSpeakerId()\npublic static  int getMaxSpeakerId()\nprivate static  byte[] defaultAccessibilityDetectionData()\nprivate  void onConstructed()\npublic  android.service.voice.VisualQueryDetectedResult.Builder buildUpon()\nclass VisualQueryDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index 1eb4d67..bf8de06 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -39,6 +39,7 @@
 import android.util.Slog;
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
+import com.android.internal.app.IVoiceInteractionAccessibilitySettingsListener;
 import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.infra.AndroidFuture;
 
@@ -61,6 +62,8 @@
 public class VisualQueryDetector {
     private static final String TAG = VisualQueryDetector.class.getSimpleName();
     private static final boolean DEBUG = false;
+    private static final int SETTINGS_DISABLE_BIT = 0;
+    private static final int SETTINGS_ENABLE_BIT = 1;
 
     private final Callback mCallback;
     private final Executor mExecutor;
@@ -68,6 +71,8 @@
     private final IVoiceInteractionManagerService mManagerService;
     private final VisualQueryDetectorInitializationDelegate mInitializationDelegate;
     private final String mAttributionTag;
+    // Used to manage the internal mapping of exposed listener API and internal aidl impl
+    private AccessibilityDetectionEnabledListenerWrapper mActiveAccessibilityListenerWrapper = null;
 
     VisualQueryDetector(
             IVoiceInteractionManagerService managerService,
@@ -174,6 +179,108 @@
         }
     }
 
+    /**
+     * Gets the binary value that controls the egress of accessibility data from
+     * {@link VisualQueryDetectedResult#setAccessibilityDetectionData(byte[])} is enabled.
+     *
+     * @return boolean value denoting if the setting is on. Default is {@code false}.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ALLOW_COMPLEX_RESULTS_EGRESS_FROM_VQDS)
+    public boolean isAccessibilityDetectionEnabled() {
+        Slog.d(TAG, "Fetching accessibility setting");
+        synchronized (mInitializationDelegate.getLock()) {
+            try {
+                return mManagerService.getAccessibilityDetectionEnabled();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Sets a listener subscribing to the value of the system setting that controls the egress of
+     * accessibility data from
+     * {@link VisualQueryDetectedResult#setAccessibilityDetectionData(byte[])} is enabled.
+     *
+     * Only one listener can be set at a time. The listener set must be unset with
+     * {@link clearAccessibilityDetectionEnabledListener(Consumer<Boolean>)}
+     * in order to set a new listener. Otherwise, this method will throw a
+     * {@link IllegalStateException}.
+     *
+     * @param listener Listener of type {@code Consumer<Boolean>} to subscribe to the value update.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ALLOW_COMPLEX_RESULTS_EGRESS_FROM_VQDS)
+    public void setAccessibilityDetectionEnabledListener(@NonNull Consumer<Boolean> listener) {
+        Slog.d(TAG, "Registering Accessibility settings listener.");
+        synchronized (mInitializationDelegate.getLock()) {
+            try {
+                if (mActiveAccessibilityListenerWrapper != null) {
+                    Slog.e(TAG, "Fail to register accessibility setting listener: "
+                            + "already registered and not unregistered.");
+                    throw new IllegalStateException(
+                            "Cannot register listener with listeners already set.");
+                }
+                mActiveAccessibilityListenerWrapper =
+                        new AccessibilityDetectionEnabledListenerWrapper(listener);
+                mManagerService.registerAccessibilityDetectionSettingsListener(
+                        mActiveAccessibilityListenerWrapper);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Clear the listener that has been set with
+     * {@link setAccessibilityDetectionEnabledListener(Consumer<Boolean>)} such that when the value
+     * of the setting that controls the egress of accessibility data is changed the listener gets
+     * notified.
+     *
+     * If there is not listener that has been registered, the call to this method will lead to a
+     * {@link IllegalStateException}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ALLOW_COMPLEX_RESULTS_EGRESS_FROM_VQDS)
+    public void clearAccessibilityDetectionEnabledListener() {
+        Slog.d(TAG, "Unregistering Accessibility settings listener.");
+        synchronized (mInitializationDelegate.getLock()) {
+            try {
+                if (mActiveAccessibilityListenerWrapper == null) {
+                    Slog.e(TAG, "Not able to remove the listener: listener does not exist.");
+                    throw new IllegalStateException("Cannot clear listener since it is not set.");
+                }
+                mManagerService.unregisterAccessibilityDetectionSettingsListener(
+                        mActiveAccessibilityListenerWrapper);
+                mActiveAccessibilityListenerWrapper = null;
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+
+    private final class AccessibilityDetectionEnabledListenerWrapper
+            extends IVoiceInteractionAccessibilitySettingsListener.Stub {
+
+        private Consumer<Boolean> mListener;
+
+        AccessibilityDetectionEnabledListenerWrapper(Consumer<Boolean> listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onAccessibilityDetectionChanged(boolean enabled) {
+            mListener.accept(enabled);
+        }
+    }
+
     /** @hide */
     public void dump(String prefix, PrintWriter pw) {
         synchronized (mInitializationDelegate.getLock()) {
diff --git a/core/java/android/service/wallpaper/Android.bp b/core/java/android/service/wallpaper/Android.bp
index a527d3d..552a07d 100644
--- a/core/java/android/service/wallpaper/Android.bp
+++ b/core/java/android/service/wallpaper/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // 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"
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 5cbbbef..2226881 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -58,6 +58,7 @@
 
     private final boolean mIsOwner;
     private final long mMemoryAddr;
+    private final int mSize;
     private int mFd = -1;
 
     /**
@@ -75,6 +76,9 @@
         final String name = UUID.randomUUID().toString();
         mFd = nativeCreate(name, size);
         mMemoryAddr = nativeOpen(mFd, mIsOwner);
+        // Note that we use the effective size after allocation, rather than the provided size,
+        // preserving compat with the original behavior. In practice these should be equivalent.
+        mSize = nativeSize(mFd);
         mCloseGuard.open("MemoryIntArray.close");
     }
 
@@ -86,6 +90,7 @@
         }
         mFd = pfd.detachFd();
         mMemoryAddr = nativeOpen(mFd, mIsOwner);
+        mSize = nativeSize(mFd);
         mCloseGuard.open("MemoryIntArray.close");
     }
 
@@ -127,13 +132,11 @@
     }
 
     /**
-     * Gets the array size.
-     *
-     * @throws IOException If an error occurs while accessing the shared memory.
+     * @return Gets the array size.
      */
-    public int size() throws IOException {
+    public int size() {
         enforceNotClosed();
-        return nativeSize(mFd);
+        return mSize;
     }
 
     /**
@@ -210,11 +213,10 @@
         }
     }
 
-    private void enforceValidIndex(int index) throws IOException {
-        final int size = size();
-        if (index < 0 || index > size - 1) {
+    private void enforceValidIndex(int index) {
+        if (index < 0 || index > mSize - 1) {
             throw new IndexOutOfBoundsException(
-                    index + " not between 0 and " + (size - 1));
+                    index + " not between 0 and " + (mSize - 1));
         }
     }
 
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 4fe53c2..a8d4e2d 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -579,6 +579,17 @@
     }
 
     /**
+     * Get the combining character that corresponds with the provided accent.
+     *
+     * @param accent The accent character.  eg. '`'
+     * @return The combining character
+     * @hide
+     */
+    public static int getCombiningChar(int accent) {
+        return sAccentToCombining.get(accent);
+    }
+
+    /**
      * Describes the character mappings associated with a key.
      *
      * @deprecated instead use {@link KeyCharacterMap#getDisplayLabel(int)},
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 715f1be..13b9c45 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -430,6 +430,11 @@
             VectorDrawable vectorDrawable) {
         Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
                 vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+        // BitmapDrawables and Bitmap have a default density of DisplayMetrics.DENSITY_DEVICE,
+        // (which is deprecated in favor of DENSITY_DEVICE_STABLE/resources.densityDpi). In
+        // rare cases when device density differs from the resource density, the bitmap will
+        // scale as the BitmapDrawable is created. Avoid by explicitly setting density here.
+        bitmap.setDensity(resources.getDisplayMetrics().densityDpi);
         Canvas canvas = new Canvas(bitmap);
         vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
         vectorDrawable.draw(canvas);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index bd9f504..83683ca 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2364,6 +2364,7 @@
 
         synchronized (mLock) {
             if (!isActiveLocked()) {
+                Log.w(TAG, "onAuthenticationResult(): sessionId=" + mSessionId + " not active");
                 return;
             }
             mState = STATE_ACTIVE;
@@ -2380,6 +2381,7 @@
             }
             if (data == null) {
                 // data is set to null when result is not RESULT_OK
+                Log.i(TAG, "onAuthenticationResult(): empty intent");
                 return;
             }
 
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index dc5e0e5..88ca2a4 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -66,6 +66,7 @@
 
     @Nullable
     private static volatile IImeTracker sTrackerServiceCache = null;
+    private static int sCurStartInputSeq = 0;
 
     /**
      * @return {@code true} if {@link IInputMethodManager} is available.
@@ -327,6 +328,7 @@
         }
     }
 
+    // TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled.
     @AnyThread
     @NonNull
     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
@@ -353,6 +355,41 @@
         }
     }
 
+    /**
+     * Returns a sequence number for startInput.
+     */
+    @AnyThread
+    @NonNull
+    @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
+    static int startInputOrWindowGainedFocusAsync(@StartInputReason int startInputReason,
+            @NonNull IInputMethodClient client, @Nullable IBinder windowToken,
+            @StartInputFlags int startInputFlags,
+            @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode,
+            @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo,
+            @Nullable IRemoteInputConnection remoteInputConnection,
+            @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
+            int unverifiedTargetSdkVersion, @UserIdInt int userId,
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
+        final IInputMethodManager service = getService();
+        if (service == null) {
+            return -1;
+        }
+        try {
+            service.startInputOrWindowGainedFocusAsync(startInputReason, client, windowToken,
+                    startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection,
+                    remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId,
+                    imeDispatcher, advanceAngGetStartInputSequenceNumber());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return sCurStartInputSeq;
+    }
+
+    private static int advanceAngGetStartInputSequenceNumber() {
+        return ++sCurStartInputSeq;
+    }
+
+
     @AnyThread
     static void showInputMethodPickerFromClient(@NonNull IInputMethodClient client,
             int auxiliarySubtypeMode) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f4b09df..72125ba 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -321,6 +321,22 @@
     };
 
     /**
+     * A runnable that reports {@link InputConnection} opened event for calls to
+     * {@link IInputMethodManagerGlobalInvoker#startInputOrWindowGainedFocusAsync}.
+     */
+    private abstract static class ReportInputConnectionOpenedRunner implements Runnable {
+        /**
+         * Sequence number to track startInput requests to
+         * {@link IInputMethodManagerGlobalInvoker#startInputOrWindowGainedFocusAsync}
+         */
+        int mSequenceNum;
+        ReportInputConnectionOpenedRunner(int sequenceNum) {
+            this.mSequenceNum = sequenceNum;
+        }
+    }
+    private ReportInputConnectionOpenedRunner mReportInputConnectionOpenedRunner;
+
+    /**
      * Ensures that {@link #sInstance} becomes non-{@code null} for application that have directly
      * or indirectly relied on {@link #sInstance} via reflection or something like that.
      *
@@ -691,6 +707,7 @@
     private static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
     private static final int MSG_SET_INTERACTIVE = 13;
     private static final int MSG_ON_SHOW_REQUESTED = 31;
+    private static final int MSG_START_INPUT_RESULT = 40;
 
     /**
      * Calling this will invalidate Local stylus handwriting availability Cache which
@@ -1045,7 +1062,7 @@
                     return;
                 }
                 case MSG_BIND: {
-                    final InputBindResult res = (InputBindResult)msg.obj;
+                    final InputBindResult res = (InputBindResult) msg.obj;
                     if (DEBUG) {
                         Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
                     }
@@ -1071,6 +1088,60 @@
                     startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0);
                     return;
                 }
+
+                case MSG_START_INPUT_RESULT: {
+                    final InputBindResult res = (InputBindResult) msg.obj;
+                    final int startInputSeq = msg.arg1;
+                    if (res == null) {
+                        // IMMS logs .wtf already.
+                        return;
+                    }
+                    if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
+                    synchronized (mH) {
+                        if (res.id != null) {
+                            updateInputChannelLocked(res.channel);
+                            mCurMethod = res.method; // for @UnsupportedAppUsage
+                            mCurBindState = new BindState(res);
+                            mAccessibilityInputMethodSession.clear();
+                            if (res.accessibilitySessions != null) {
+                                for (int i = 0; i < res.accessibilitySessions.size(); i++) {
+                                    IAccessibilityInputMethodSessionInvoker wrapper =
+                                            IAccessibilityInputMethodSessionInvoker.createOrNull(
+                                                    res.accessibilitySessions.valueAt(i));
+                                    if (wrapper != null) {
+                                        mAccessibilityInputMethodSession.append(
+                                                res.accessibilitySessions.keyAt(i), wrapper);
+                                    }
+                                }
+                            }
+                            mCurId = res.id; // for @UnsupportedAppUsage
+                        } else if (res.channel != null && res.channel != mCurChannel) {
+                            res.channel.dispose();
+                        }
+                        switch (res.result) {
+                            case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
+                                mRestartOnNextWindowFocus = true;
+                                mServedView = null;
+                                break;
+                        }
+                        if (mCompletions != null) {
+                            if (isImeSessionAvailableLocked()) {
+                                mCurBindState.mImeSession.displayCompletions(mCompletions);
+                            }
+                        }
+
+                        if (res != null
+                                && res.method != null
+                                && mServedView != null
+                                && mReportInputConnectionOpenedRunner != null
+                                && mReportInputConnectionOpenedRunner.mSequenceNum
+                                        == startInputSeq) {
+                            mReportInputConnectionOpenedRunner.run();
+                        }
+                        mReportInputConnectionOpenedRunner = null;
+                    }
+                    return;
+                }
                 case MSG_UNBIND: {
                     final int sequence = msg.arg1;
                     @UnbindReason
@@ -1322,6 +1393,12 @@
         }
 
         @Override
+        public void onStartInputResult(InputBindResult res, int startInputSeq) {
+            mH.obtainMessage(MSG_START_INPUT_RESULT, startInputSeq, -1 /* unused */, res)
+                    .sendToTarget();
+        }
+
+        @Override
         public void onBindAccessibilityService(InputBindResult res, int id) {
             mH.obtainMessage(MSG_BIND_ACCESSIBILITY_SERVICE, id, 0, res).sendToTarget();
         }
@@ -2010,6 +2087,7 @@
             mServedConnecting = false;
             clearConnectionLocked();
         }
+        mReportInputConnectionOpenedRunner = null;
         // Clear the back callbacks held by the ime dispatcher to avoid memory leaks.
         mImeDispatcher.clear();
     }
@@ -3080,14 +3158,52 @@
             final int targetUserId = editorInfo.targetInputMethodUser != null
                     ? editorInfo.targetInputMethodUser.getIdentifier() : UserHandle.myUserId();
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMM.startInputOrWindowGainedFocus");
-            res = IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus(
-                    startInputReason, mClient, windowGainingFocus, startInputFlags,
-                    softInputMode, windowFlags, editorInfo, servedInputConnection,
-                    servedInputConnection == null ? null
-                            : servedInputConnection.asIRemoteAccessibilityInputConnection(),
-                    view.getContext().getApplicationInfo().targetSdkVersion, targetUserId,
-                    mImeDispatcher);
+
+            int startInputSeq = -1;
+            if (Flags.useZeroJankProxy()) {
+                // async result delivered via MSG_START_INPUT_RESULT.
+                startInputSeq = IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocusAsync(
+                        startInputReason, mClient, windowGainingFocus, startInputFlags,
+                        softInputMode, windowFlags, editorInfo, servedInputConnection,
+                        servedInputConnection == null ? null
+                                : servedInputConnection.asIRemoteAccessibilityInputConnection(),
+                        view.getContext().getApplicationInfo().targetSdkVersion, targetUserId,
+                        mImeDispatcher);
+            } else {
+                res = IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus(
+                        startInputReason, mClient, windowGainingFocus, startInputFlags,
+                        softInputMode, windowFlags, editorInfo, servedInputConnection,
+                        servedInputConnection == null ? null
+                                : servedInputConnection.asIRemoteAccessibilityInputConnection(),
+                        view.getContext().getApplicationInfo().targetSdkVersion, targetUserId,
+                        mImeDispatcher);
+            }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            if (Flags.useZeroJankProxy()) {
+                // Create a runnable for delayed notification to the app that the InputConnection is
+                // initialized and ready for use.
+                if (ic != null) {
+                    final int seqId = startInputSeq;
+                    mReportInputConnectionOpenedRunner =
+                            new ReportInputConnectionOpenedRunner(startInputSeq) {
+                                @Override
+                                public void run() {
+                                    if (DEBUG) {
+                                        Log.v(TAG, "Calling View.onInputConnectionOpened: view= "
+                                                + view
+                                                + ", ic=" + ic + ", editorInfo=" + editorInfo
+                                                + ", handler="
+                                                + icHandler + ", startInputSeq=" + seqId);
+                                    }
+                                    reportInputConnectionOpened(ic, editorInfo, icHandler, view);
+                                }
+                            };
+                } else {
+                    mReportInputConnectionOpenedRunner = null;
+                }
+                return true;
+            }
+
             if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
             if (res == null) {
                 Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
@@ -3118,6 +3234,7 @@
             } else if (res.channel != null && res.channel != mCurChannel) {
                 res.channel.dispose();
             }
+
             switch (res.result) {
                 case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
                     mRestartOnNextWindowFocus = true;
diff --git a/core/java/com/android/internal/app/IVoiceInteractionAccessibilitySettingsListener.aidl b/core/java/com/android/internal/app/IVoiceInteractionAccessibilitySettingsListener.aidl
new file mode 100644
index 0000000..a919035
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractionAccessibilitySettingsListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app;
+
+oneway interface IVoiceInteractionAccessibilitySettingsListener {
+   /**
+    * Called when the value of secure setting has changed.
+    */
+   void onAccessibilityDetectionChanged(boolean enable);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 314ed69..98d39397 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -35,6 +35,7 @@
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVoiceActionCheckCallback;
+import com.android.internal.app.IVoiceInteractionAccessibilitySettingsListener;
 import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
@@ -382,4 +383,21 @@
     oneway void notifyActivityEventChanged(
             in IBinder activityToken,
             int type);
+
+    /**
+     * rely on the system server to get the secure settings
+     */
+    boolean getAccessibilityDetectionEnabled();
+
+    /**
+     * register the listener
+     */
+    oneway void registerAccessibilityDetectionSettingsListener(
+            in IVoiceInteractionAccessibilitySettingsListener listener);
+
+    /**
+     * unregister the listener
+     */
+     oneway void unregisterAccessibilityDetectionSettingsListener(
+            in IVoiceInteractionAccessibilitySettingsListener listener);
 }
diff --git a/core/java/com/android/internal/colorextraction/OWNERS b/core/java/com/android/internal/colorextraction/OWNERS
index ffade1e..041559c 100644
--- a/core/java/com/android/internal/colorextraction/OWNERS
+++ b/core/java/com/android/internal/colorextraction/OWNERS
@@ -1,3 +1,2 @@
-dupin@google.com
 cinek@google.com
-jamesoleary@google.com
+arteiro@google.com
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl b/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl
index 9251d2d..babd9a0 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl
@@ -24,6 +24,7 @@
  */
 oneway interface IInputMethodClient {
     void onBindMethod(in InputBindResult res);
+    void onStartInputResult(in InputBindResult res, int startInputSeq);
     void onBindAccessibilityService(in InputBindResult res, int id);
     void onUnbindMethod(int sequence, int unbindReason);
     void onUnbindAccessibilityService(int sequence, int id);
diff --git a/core/java/com/android/internal/inputmethod/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
index b6eca07..243b103 100644
--- a/core/java/com/android/internal/inputmethod/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -271,6 +271,7 @@
     public String toString() {
         return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
                 + " sequence=" + sequence
+                + " result=" + result
                 + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
                 + "}";
     }
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 48c455a..3662d69 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -120,7 +120,7 @@
     public static final int CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY = 84;
     public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = 85;
     public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
-    public static final int CUJ_LAUNCHER_SEARCH_QSB_OPEN = 87;
+    // 87 is reserved - previously assigned to deprecated CUJ_LAUNCHER_SEARCH_QSB_OPEN.
     public static final int CUJ_BACK_PANEL_ARROW = 88;
     public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK = 89;
     public static final int CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH = 90;
@@ -209,7 +209,6 @@
             CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY,
             CUJ_PREDICTIVE_BACK_CROSS_TASK,
             CUJ_PREDICTIVE_BACK_HOME,
-            CUJ_LAUNCHER_SEARCH_QSB_OPEN,
             CUJ_BACK_PANEL_ARROW,
             CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK,
             CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH,
@@ -304,7 +303,6 @@
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_TASK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
-        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_BACK_PANEL_ARROW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BACK_PANEL_ARROW;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_BACK;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_WEB_SEARCH;
@@ -480,8 +478,6 @@
                 return "PREDICTIVE_BACK_CROSS_TASK";
             case CUJ_PREDICTIVE_BACK_HOME:
                 return "PREDICTIVE_BACK_HOME";
-            case CUJ_LAUNCHER_SEARCH_QSB_OPEN:
-                return "LAUNCHER_SEARCH_QSB_OPEN";
             case CUJ_BACK_PANEL_ARROW:
                 return "BACK_PANEL_ARROW";
             case CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK:
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ed43b81..d463b62 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -376,4 +376,10 @@
      * @param packageName of the session for which the output switcher is shown.
      */
     void showMediaOutputSwitcher(String packageName);
+
+    /** Enters desktop mode.
+    *
+    * @param displayId the id of the current display.
+    */
+    void enterDesktop(int displayId);
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index e95127b..b90f8bf 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -69,6 +69,8 @@
     boolean hideSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
             in @nullable ImeTracker.Token statsToken, int flags,
             in @nullable ResultReceiver resultReceiver, int reason);
+
+    // TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled.
     // If windowToken is null, this just does startInput().  Otherwise this reports that a window
     // has gained focus, and if 'editorInfo' is non-null then also does startInput.
     // @NonNull
@@ -85,6 +87,21 @@
             int unverifiedTargetSdkVersion, int userId,
             in ImeOnBackInvokedDispatcher imeDispatcher);
 
+    // If windowToken is null, this just does startInput().  Otherwise this reports that a window
+    // has gained focus, and if 'editorInfo' is non-null then also does startInput.
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
+    void startInputOrWindowGainedFocusAsync(
+            /* @StartInputReason */ int startInputReason,
+            in IInputMethodClient client, in @nullable IBinder windowToken,
+            /* @StartInputFlags */ int startInputFlags,
+            /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
+            /* @android.view.WindowManager.LayoutParams.Flags */ int windowFlags,
+            in @nullable EditorInfo editorInfo, in @nullable IRemoteInputConnection inputConnection,
+            in @nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
+            int unverifiedTargetSdkVersion, int userId,
+            in ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq);
+
     void showInputMethodPickerFromClient(in IInputMethodClient client,
             int auxiliarySubtypeMode);
 
@@ -156,6 +173,7 @@
                 in String delegatePackageName,
                 in String delegatorPackageName);
 
+    // TODO(b/293640003): introduce a new API method to provide async way to return boolean.
     /** Accepts and starts a stylus handwriting session for the delegate view **/
     boolean acceptStylusHandwritingDelegation(in IInputMethodClient client, in int userId,
             in String delegatePackageName, in String delegatorPackageName, int flags);
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 3ee15ab..3d0ab4e 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -314,7 +314,8 @@
 }
 
 static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                               jobjectArray apk_assets_array, jboolean invalidate_caches) {
+                               jobjectArray apk_assets_array, jboolean invalidate_caches,
+                               jboolean preset) {
   ATRACE_NAME("AssetManager::SetApkAssets");
 
   const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
@@ -343,7 +344,11 @@
   }
 
   auto assetmanager = LockAndStartAssetManager(ptr);
-  assetmanager->SetApkAssets(apk_assets, invalidate_caches);
+  if (preset) {
+    assetmanager->PresetApkAssets(apk_assets);
+  } else {
+    assetmanager->SetApkAssets(apk_assets, invalidate_caches);
+  }
 }
 
 static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
@@ -353,7 +358,7 @@
                                    jint screen_height, jint smallest_screen_width_dp,
                                    jint screen_width_dp, jint screen_height_dp, jint screen_layout,
                                    jint ui_mode, jint color_mode, jint grammatical_gender,
-                                   jint major_version) {
+                                   jint major_version, jboolean force_refresh) {
   ATRACE_NAME("AssetManager::SetConfiguration");
 
   const jsize locale_count = (locales == NULL) ? 0 : env->GetArrayLength(locales);
@@ -413,7 +418,7 @@
   }
 
   auto assetmanager = LockAndStartAssetManager(ptr);
-  assetmanager->SetConfigurations(configs);
+  assetmanager->SetConfigurations(std::move(configs), force_refresh != JNI_FALSE);
   assetmanager->SetDefaultLocale(default_locale_int);
 }
 
@@ -1522,8 +1527,8 @@
         // AssetManager setup methods.
         {"nativeCreate", "()J", (void*)NativeCreate},
         {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-        {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
-        {"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIII)V",
+        {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;ZZ)V", (void*)NativeSetApkAssets},
+        {"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIIIZ)V",
          (void*)NativeSetConfiguration},
         {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
          (void*)NativeGetAssignedPackageIdentifiers},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 33af172..0b3a065 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2281,7 +2281,7 @@
     <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
         credentials such as Network Key and PSKc.
         <p>Not for use by third-party applications.
-        @FlaggedApi("com.android.net.thread.flags.thread_enabled") -->
+        @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") -->
     <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
                 android:protectionLevel="signature|privileged" />
 
@@ -7937,6 +7937,33 @@
     <permission android:name="android.permission.MANAGE_WEARABLE_SENSING_SERVICE"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an app to use the on-device intelligence service.
+             <p>Protection level: signature|privileged
+             @hide
+         @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")
+        -->
+    <permission android:name="android.permission.USE_ON_DEVICE_INTELLIGENCE"
+        android:protectionLevel="signature|privileged" />
+
+
+    <!-- @SystemApi Allows an app to bind the on-device intelligence service.
+             <p>Protection level: signature|privileged
+             @hide
+         @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")
+        -->
+    <permission android:name="android.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE"
+        android:protectionLevel="signature|privileged" />
+
+
+    <!-- @SystemApi Allows an app to bind the on-device trusted service.
+             <p>Protection level: signature|privileged
+             @hide
+         @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")
+        -->
+    <permission android:name="android.permission.BIND_ON_DEVICE_TRUSTED_SERVICE"
+        android:protectionLevel="signature"/>
+
+
     <!-- Allows applications to use the user-initiated jobs API. For more details
          see {@link android.app.job.JobInfo.Builder#setUserInitiated}.
          <p>Protection level: normal
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c6bc589..1f06b0b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4670,6 +4670,13 @@
    -->
     <string name="config_defaultWearableSensingService" translatable="false"></string>
 
+
+    <!-- The component name for the default system on-device intelligence service, -->
+    <string name="config_defaultOnDeviceIntelligenceService" translatable="false"></string>
+
+    <!-- The component name for the default system on-device trusted inference service. -->
+    <string name="config_defaultOnDeviceTrustedInferenceService" translatable="false"></string>
+
     <!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent for
          wearable sensing. -->
     <string translatable="false" name="config_defaultWearableSensingConsentComponent"></string>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index fa15c3f..972fe7e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -204,11 +204,4 @@
     <dimen name="progress_bar_size_small">16dip</dimen>
     <dimen name="progress_bar_size_medium">48dp</dimen>
     <dimen name="progress_bar_size_large">76dp</dimen>
-
-    <!-- System corner radius baseline sizes. Used by Material styling of rounded corner shapes-->
-    <dimen name="system_corner_radius_xsmall">4dp</dimen>
-    <dimen name="system_corner_radius_small">8dp</dimen>
-    <dimen name="system_corner_radius_medium">16dp</dimen>
-    <dimen name="system_corner_radius_large">26dp</dimen>
-    <dimen name="system_corner_radius_xlarge">36dp</dimen>
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index c797210..5987f6e 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -184,11 +184,11 @@
 
   <staging-public-group type="dimen" first-id="0x01b90000">
     <!-- System corner radius baseline sizes. Used by Material styling of rounded corner shapes-->
-    <public name="system_corner_radius_xsmall" />
-    <public name="system_corner_radius_small" />
-    <public name="system_corner_radius_medium" />
-    <public name="system_corner_radius_large" />
-    <public name="system_corner_radius_xlarge" />
+    <public name="removed_system_corner_radius_xsmall" />
+    <public name="removed_system_corner_radius_small" />
+    <public name="removed_system_corner_radius_medium" />
+    <public name="removed_system_corner_radius_large" />
+    <public name="removed_system_corner_radius_xlarge" />
   </staging-public-group>
 
   <staging-public-group type="color" first-id="0x01b80000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7c290b1..cf9c02a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3909,6 +3909,8 @@
   <java-symbol type="string" name="config_ambientContextPackageNameExtraKey" />
   <java-symbol type="string" name="config_ambientContextEventArrayExtraKey" />
   <java-symbol type="string" name="config_defaultWearableSensingService" />
+  <java-symbol type="string" name="config_defaultOnDeviceIntelligenceService" />
+  <java-symbol type="string" name="config_defaultOnDeviceTrustedInferenceService" />
   <java-symbol type="string" name="config_retailDemoPackage" />
   <java-symbol type="string" name="config_retailDemoPackageSignature" />
 
@@ -5356,11 +5358,4 @@
   <java-symbol type="drawable" name="ic_satellite_alt_24px" />
 
   <java-symbol type="bool" name="config_watchlistUseFileHashesCache" />
-
-  <!-- System corner radius baseline sizes. Used by Material styling of rounded corner shapes-->
-  <java-symbol type="dimen" name="system_corner_radius_xsmall" />
-  <java-symbol type="dimen" name="system_corner_radius_small" />
-  <java-symbol type="dimen" name="system_corner_radius_medium" />
-  <java-symbol type="dimen" name="system_corner_radius_large" />
-  <java-symbol type="dimen" name="system_corner_radius_xlarge" />
 </resources>
diff --git a/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java b/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java
new file mode 100644
index 0000000..aaa199d
--- /dev/null
+++ b/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.usb.UsbDevice;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.Flags;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Tests for internal details of BrailleDisplayControllerImpl.
+ *
+ * <p>Prefer adding new tests in CTS where possible.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@RequiresFlagsEnabled(Flags.FLAG_BRAILLE_DISPLAY_HID)
+public class BrailleDisplayControllerImplTest {
+    private static final int TEST_SERVICE_CONNECTION_ID = 123;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    private BrailleDisplayController mBrailleDisplayController;
+
+    @Mock
+    private IAccessibilityServiceConnection mAccessibilityServiceConnection;
+    @Mock
+    private BrailleDisplayController.BrailleDisplayCallback mBrailleDisplayCallback;
+
+    public static class TestAccessibilityService extends AccessibilityService {
+        public void onAccessibilityEvent(AccessibilityEvent event) {
+        }
+
+        public void onInterrupt() {
+        }
+    }
+
+    @Before
+    public void test() {
+        MockitoAnnotations.initMocks(this);
+        AccessibilityService accessibilityService = spy(new TestAccessibilityService());
+        doReturn((Executor) Runnable::run).when(accessibilityService).getMainExecutor();
+        doReturn(TEST_SERVICE_CONNECTION_ID).when(accessibilityService).getConnectionId();
+        AccessibilityInteractionClient.addConnection(TEST_SERVICE_CONNECTION_ID,
+                mAccessibilityServiceConnection, /*initializeCache=*/false);
+        mBrailleDisplayController = accessibilityService.getBrailleDisplayController();
+    }
+
+    // Automated CTS tests only use the BluetoothDevice version of BrailleDisplayController#connect
+    // because fake UsbDevice objects cannot be created in CTS. This internal test can mock the
+    // UsbDevice object and at least validate that the correct system_server AIDL call is made.
+    @Test
+    public void connect_withUsbDevice_callsConnectUsbBrailleDisplay() throws Exception {
+        UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+
+        mBrailleDisplayController.connect(usbDevice, mBrailleDisplayCallback);
+
+        verify(mAccessibilityServiceConnection).connectUsbBrailleDisplay(eq(usbDevice), any());
+    }
+
+    @Test
+    public void connect_serviceNotConnected_throwsIllegalStateException() {
+        AccessibilityInteractionClient.removeConnection(TEST_SERVICE_CONNECTION_ID);
+        UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+
+        assertThrows(IllegalStateException.class,
+                () -> mBrailleDisplayController.connect(usbDevice, mBrailleDisplayCallback));
+    }
+}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 48ef7e6..ebf4cca 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -43,7 +43,6 @@
 import android.app.PictureInPictureUiState;
 import android.app.ResourcesManager;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
-import android.app.servertransaction.ActivityLifecycleItem;
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.ClientTransactionItem;
@@ -75,7 +74,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.content.ReferrerIntent;
-import com.android.window.flags.Flags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -230,7 +228,7 @@
         try {
             // Send process level config change.
             ClientTransaction transaction = newTransaction(activityThread);
-            addClientTransactionItem(transaction, ConfigurationChangeItem.obtain(
+            transaction.addTransactionItem(ConfigurationChangeItem.obtain(
                     newConfig, DEVICE_ID_INVALID));
             appThread.scheduleTransaction(transaction);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -247,7 +245,7 @@
             newConfig.seq++;
             newConfig.smallestScreenWidthDp++;
             transaction = newTransaction(activityThread);
-            addClientTransactionItem(transaction, ActivityConfigurationChangeItem.obtain(
+            transaction.addTransactionItem(ActivityConfigurationChangeItem.obtain(
                     activity.getActivityToken(), newConfig));
             appThread.scheduleTransaction(transaction);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -448,16 +446,16 @@
         activity.mTestLatch = new CountDownLatch(1);
 
         ClientTransaction transaction = newTransaction(activityThread);
-        addClientTransactionItem(transaction, ConfigurationChangeItem.obtain(
+        transaction.addTransactionItem(ConfigurationChangeItem.obtain(
                 processConfigLandscape, DEVICE_ID_INVALID));
         appThread.scheduleTransaction(transaction);
 
         transaction = newTransaction(activityThread);
-        addClientTransactionItem(transaction, ActivityConfigurationChangeItem.obtain(
+        transaction.addTransactionItem(ActivityConfigurationChangeItem.obtain(
                 activity.getActivityToken(), activityConfigLandscape));
-        addClientTransactionItem(transaction, ConfigurationChangeItem.obtain(
+        transaction.addTransactionItem(ConfigurationChangeItem.obtain(
                 processConfigPortrait, DEVICE_ID_INVALID));
-        addClientTransactionItem(transaction, ActivityConfigurationChangeItem.obtain(
+        transaction.addTransactionItem(ActivityConfigurationChangeItem.obtain(
                 activity.getActivityToken(), activityConfigPortrait));
         appThread.scheduleTransaction(transaction);
 
@@ -847,8 +845,8 @@
                         false /* shouldSendCompatFakeFocus*/);
 
         final ClientTransaction transaction = newTransaction(activity);
-        addClientTransactionItem(transaction, callbackItem);
-        addClientTransactionItem(transaction, resumeStateRequest);
+        transaction.addTransactionItem(callbackItem);
+        transaction.addTransactionItem(resumeStateRequest);
 
         return transaction;
     }
@@ -860,7 +858,7 @@
                         false /* shouldSendCompatFakeFocus */);
 
         final ClientTransaction transaction = newTransaction(activity);
-        addClientTransactionItem(transaction, resumeStateRequest);
+        transaction.addTransactionItem(resumeStateRequest);
 
         return transaction;
     }
@@ -871,7 +869,7 @@
                 activity.getActivityToken(), 0 /* configChanges */);
 
         final ClientTransaction transaction = newTransaction(activity);
-        addClientTransactionItem(transaction, stopStateRequest);
+        transaction.addTransactionItem(stopStateRequest);
 
         return transaction;
     }
@@ -883,7 +881,7 @@
                 activity.getActivityToken(), config);
 
         final ClientTransaction transaction = newTransaction(activity);
-        addClientTransactionItem(transaction, item);
+        transaction.addTransactionItem(item);
 
         return transaction;
     }
@@ -895,7 +893,7 @@
                 resume);
 
         final ClientTransaction transaction = newTransaction(activity);
-        addClientTransactionItem(transaction, item);
+        transaction.addTransactionItem(item);
 
         return transaction;
     }
@@ -910,17 +908,6 @@
         return ClientTransaction.obtain(activityThread.getApplicationThread());
     }
 
-    private static void addClientTransactionItem(@NonNull ClientTransaction transaction,
-            @NonNull ClientTransactionItem item) {
-        if (Flags.bundleClientTransactionFlag()) {
-            transaction.addTransactionItem(item);
-        } else if (item.isActivityLifecycleItem()) {
-            transaction.setLifecycleStateRequest((ActivityLifecycleItem) item);
-        } else {
-            transaction.addCallback(item);
-        }
-    }
-
     // Test activity
     public static class TestActivity extends Activity {
         static final String PIP_REQUESTED_OVERRIDE_ENTER = "pip_requested_override_enter";
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index 95d5049..213fd7b 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -16,10 +16,13 @@
 
 package android.app.servertransaction;
 
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
+
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.hardware.display.DisplayManager;
@@ -28,12 +31,14 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.view.DisplayInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -49,6 +54,10 @@
 @SmallTest
 @Presubmit
 public class ClientTransactionListenerControllerTest {
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
     @Mock
     private IDisplayManager mIDisplayManager;
     @Mock
@@ -60,12 +69,12 @@
 
     @Before
     public void setup() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
         MockitoAnnotations.initMocks(this);
         mDisplayManager = new DisplayManagerGlobal(mIDisplayManager);
         mHandler = getInstrumentation().getContext().getMainThreadHandler();
-        mController = spy(ClientTransactionListenerController.createInstanceForTesting(
-                mDisplayManager));
-        doReturn(true).when(mController).isBundleClientTransactionFlagEnabled();
+        mController = ClientTransactionListenerController.createInstanceForTesting(mDisplayManager);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
index d10cf16..5272416 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -16,16 +16,22 @@
 
 package android.app.servertransaction;
 
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
+
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.app.ClientTransactionHandler;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -43,31 +49,28 @@
 @Presubmit
 public class ClientTransactionTests {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
     @Test
     public void testPreExecute() {
-        final ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
-        final ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
-        final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
-        final ClientTransactionHandler clientTransactionHandler =
-                mock(ClientTransactionHandler.class);
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
-        final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        transaction.addCallback(callback1);
-        transaction.addCallback(callback2);
-        transaction.setLifecycleStateRequest(stateRequest);
-
-        transaction.preExecute(clientTransactionHandler);
-
-        verify(callback1, times(1)).preExecute(clientTransactionHandler);
-        verify(callback2, times(1)).preExecute(clientTransactionHandler);
-        verify(stateRequest, times(1)).preExecute(clientTransactionHandler);
+        testPreExecuteInner();
     }
 
     @Test
-    public void testPreExecuteTransactionItems() {
+    public void testPreExecute_bundleClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+        testPreExecuteInner();
+    }
+
+    private void testPreExecuteInner() {
         final ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
         final ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
         final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
+        doReturn(true).when(stateRequest).isActivityLifecycleItem();
         final ClientTransactionHandler clientTransactionHandler =
                 mock(ClientTransactionHandler.class);
 
@@ -78,8 +81,8 @@
 
         transaction.preExecute(clientTransactionHandler);
 
-        verify(callback1, times(1)).preExecute(clientTransactionHandler);
-        verify(callback2, times(1)).preExecute(clientTransactionHandler);
-        verify(stateRequest, times(1)).preExecute(clientTransactionHandler);
+        verify(callback1).preExecute(clientTransactionHandler);
+        verify(callback2).preExecute(clientTransactionHandler);
+        verify(stateRequest).preExecute(clientTransactionHandler);
     }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index 2315a58..adb6f2a 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -25,6 +25,9 @@
 import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
 import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
 import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -51,12 +54,14 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArrayMap;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
@@ -83,6 +88,9 @@
 @Presubmit
 public class TransactionExecutorTests {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
     @Mock
     private ClientTransactionHandler mTransactionHandler;
     @Mock
@@ -240,29 +248,19 @@
 
     @Test
     public void testTransactionResolution() {
-        ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
-        when(callback1.getPostExecutionState()).thenReturn(UNDEFINED);
-        ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
-        when(callback2.getPostExecutionState()).thenReturn(UNDEFINED);
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
-        ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        transaction.addCallback(callback1);
-        transaction.addCallback(callback2);
-        transaction.setLifecycleStateRequest(mActivityLifecycleItem);
-
-        transaction.preExecute(mTransactionHandler);
-        mExecutor.execute(transaction);
-
-        InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2,
-                mActivityLifecycleItem);
-        inOrder.verify(callback1).execute(eq(mTransactionHandler), any());
-        inOrder.verify(callback2).execute(eq(mTransactionHandler), any());
-        inOrder.verify(mActivityLifecycleItem).execute(eq(mTransactionHandler), eq(mClientRecord),
-                any());
+        testTransactionResolutionInner();
     }
 
     @Test
-    public void testExecuteTransactionItems_transactionResolution() {
+    public void testTransactionResolution_bundleClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+        testTransactionResolutionInner();
+    }
+
+    private void testTransactionResolutionInner() {
         ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
         when(callback1.getPostExecutionState()).thenReturn(UNDEFINED);
         ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
@@ -286,38 +284,19 @@
 
     @Test
     public void testDoNotLaunchDestroyedActivity() {
-        final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
-        when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed);
-        // Assume launch transaction is still in queue, so there is no client record.
-        when(mTransactionHandler.getActivityClient(any())).thenReturn(null);
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
-        // An incoming destroy transaction enters binder thread (preExecute).
-        final IBinder token = mock(IBinder.class);
-        final ClientTransaction destroyTransaction = ClientTransaction.obtain(null /* client */);
-        destroyTransaction.setLifecycleStateRequest(
-                DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */));
-        destroyTransaction.preExecute(mTransactionHandler);
-        // The activity should be added to to-be-destroyed container.
-        assertEquals(1, activitiesToBeDestroyed.size());
-
-        // A previous queued launch transaction runs on main thread (execute).
-        final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */);
-        final LaunchActivityItem launchItem =
-                spy(new LaunchActivityItemBuilder(token, new Intent(), new ActivityInfo()).build());
-        launchTransaction.addCallback(launchItem);
-        mExecutor.execute(launchTransaction);
-
-        // The launch transaction should not be executed because its token is in the
-        // to-be-destroyed container.
-        verify(launchItem, never()).execute(any(), any());
-
-        // After the destroy transaction has been executed, the token should be removed.
-        mExecutor.execute(destroyTransaction);
-        assertTrue(activitiesToBeDestroyed.isEmpty());
+        testDoNotLaunchDestroyedActivityInner();
     }
 
     @Test
-    public void testExecuteTransactionItems_doNotLaunchDestroyedActivity() {
+    public void testDoNotLaunchDestroyedActivity_bundleClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+        testDoNotLaunchDestroyedActivityInner();
+    }
+
+    private void testDoNotLaunchDestroyedActivityInner() {
         final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
         when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed);
         // Assume launch transaction is still in queue, so there is no client record.
@@ -350,26 +329,19 @@
 
     @Test
     public void testActivityResultRequiredStateResolution() {
-        when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
-        PostExecItem postExecItem = new PostExecItem(ON_RESUME);
-
-        ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        transaction.addCallback(postExecItem);
-
-        // Verify resolution that should get to onPause
-        mClientRecord.setState(ON_RESUME);
-        mExecutor.executeCallbacks(transaction);
-        verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction));
-
-        // Verify resolution that should get to onStart
-        mClientRecord.setState(ON_STOP);
-        mExecutor.executeCallbacks(transaction);
-        verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
+        testActivityResultRequiredStateResolutionInner();
     }
 
     @Test
-    public void testExecuteTransactionItems_activityResultRequiredStateResolution() {
+    public void testActivityResultRequiredStateResolution_bundleClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+        testActivityResultRequiredStateResolutionInner();
+    }
+
+    private void testActivityResultRequiredStateResolutionInner() {
         when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
 
         PostExecItem postExecItem = new PostExecItem(ON_RESUME);
@@ -379,12 +351,12 @@
 
         // Verify resolution that should get to onPause
         mClientRecord.setState(ON_RESUME);
-        mExecutor.executeTransactionItems(transaction);
+        mExecutor.execute(transaction);
         verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction));
 
         // Verify resolution that should get to onStart
         mClientRecord.setState(ON_STOP);
-        mExecutor.executeTransactionItems(transaction);
+        mExecutor.execute(transaction);
         verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
     }
 
@@ -523,18 +495,19 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void testActivityItemNullRecordThrowsException() {
-        final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
-        when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
-        final IBinder token = mock(IBinder.class);
-        final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        transaction.addCallback(activityItem);
-        when(mTransactionHandler.getActivityClient(token)).thenReturn(null);
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
-        mExecutor.executeCallbacks(transaction);
+        testActivityItemNullRecordThrowsExceptionInner();
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void testExecuteTransactionItems_activityItemNullRecordThrowsException() {
+    public void testActivityItemNullRecordThrowsException_bundleClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+        testActivityItemNullRecordThrowsExceptionInner();
+    }
+
+    private void testActivityItemNullRecordThrowsExceptionInner() {
         final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
         when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
         final IBinder token = mock(IBinder.class);
@@ -542,28 +515,24 @@
         transaction.addTransactionItem(activityItem);
         when(mTransactionHandler.getActivityClient(token)).thenReturn(null);
 
-        mExecutor.executeTransactionItems(transaction);
+        mExecutor.execute(transaction);
     }
 
     @Test
     public void testActivityItemExecute() {
-        final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
-        when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
-        when(activityItem.getActivityToken()).thenReturn(mActivityToken);
-        transaction.addCallback(activityItem);
-        transaction.setLifecycleStateRequest(mActivityLifecycleItem);
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
-        mExecutor.execute(transaction);
-
-        final InOrder inOrder = inOrder(activityItem, mActivityLifecycleItem);
-        inOrder.verify(activityItem).execute(eq(mTransactionHandler), eq(mClientRecord), any());
-        inOrder.verify(mActivityLifecycleItem).execute(eq(mTransactionHandler), eq(mClientRecord),
-                any());
+        testActivityItemExecuteInner();
     }
 
     @Test
-    public void testExecuteTransactionItems_activityItemExecute() {
+    public void testActivityItemExecute_bundleClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
+        testActivityItemExecuteInner();
+    }
+
+    private void testActivityItemExecuteInner() {
         final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
         final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
         when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index c30d216..aa80013 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -20,6 +20,9 @@
 import static android.app.servertransaction.TestUtils.mergedConfig;
 import static android.app.servertransaction.TestUtils.referrerIntentList;
 import static android.app.servertransaction.TestUtils.resultInfoList;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
 
 import static org.junit.Assert.assertEquals;
 
@@ -36,11 +39,13 @@
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -60,6 +65,9 @@
 @Presubmit
 public class TransactionParcelTests {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
     private Parcel mParcel;
     private IBinder mActivityToken;
 
@@ -275,6 +283,8 @@
 
     @Test
     public void testClientTransaction() {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
         // Write to parcel
         NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true);
         ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
@@ -300,14 +310,16 @@
 
     @Test
     public void testClientTransactionCallbacksOnly() {
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
         // Write to parcel
         NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true);
         ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
                 mActivityToken, config());
 
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        transaction.addCallback(callback1);
-        transaction.addCallback(callback2);
+        transaction.addTransactionItem(callback1);
+        transaction.addTransactionItem(callback2);
 
         writeAndPrepareForReading(transaction);
 
@@ -321,12 +333,14 @@
 
     @Test
     public void testClientTransactionLifecycleOnly() {
+        mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
         // Write to parcel
         StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken,
                 78 /* configChanges */);
 
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
-        transaction.setLifecycleStateRequest(lifecycleRequest);
+        transaction.addTransactionItem(lifecycleRequest);
 
         writeAndPrepareForReading(transaction);
 
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
index fb5e512..c287721 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateTest.java
@@ -57,19 +57,15 @@
 
     @Test
     public void testConstruct_tooLargeIdentifier() {
-        assertThrows(IllegalArgumentException.class, () -> {
-            final DeviceState state = new DeviceState(
-                    MAXIMUM_DEVICE_STATE_IDENTIFIER + 1 /* identifier */,
-                    null /* name */, 0 /* flags */);
-        });
+        assertThrows(IllegalArgumentException.class,
+                () -> new DeviceState(MAXIMUM_DEVICE_STATE_IDENTIFIER + 1 /* identifier */,
+                        null /* name */, 0 /* flags */));
     }
 
     @Test
     public void testConstruct_tooSmallIdentifier() {
-        assertThrows(IllegalArgumentException.class, () -> {
-            final DeviceState state = new DeviceState(
-                    MINIMUM_DEVICE_STATE_IDENTIFIER - 1 /* identifier */,
-                    null /* name */, 0 /* flags */);
-        });
+        assertThrows(IllegalArgumentException.class,
+                () -> new DeviceState(MINIMUM_DEVICE_STATE_IDENTIFIER - 1 /* identifier */,
+                        null /* name */, 0 /* flags */));
     }
 }
diff --git a/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java b/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
index 51013e4..8093af9 100644
--- a/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
+++ b/core/tests/utiltests/src/android/util/MemoryIntArrayTest.java
@@ -123,7 +123,7 @@
             parcel.recycle();
 
             assertNotNull("Should marshall file descriptor", secondArray);
-
+            assertEquals("Marshalled size must be three", 3, secondArray.size());
             assertEquals("First element should be 1", 1, secondArray.get(0));
             assertEquals("First element should be 2", 2, secondArray.get(1));
             assertEquals("First element should be 3", 3, secondArray.get(2));
diff --git a/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java b/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java
index 9264c6c..32dda6b 100644
--- a/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java
+++ b/core/tests/utiltests/src/android/util/RemoteMemoryIntArrayService.java
@@ -84,11 +84,7 @@
             @Override
             public int size() {
                 synchronized (mLock) {
-                    try {
-                        return mArray.size();
-                    } catch (IOException e) {
-                        throw new IllegalStateException(e);
-                    }
+                    return mArray.size();
                 }
             }
 
diff --git a/core/tests/vibrator/Android.bp b/core/tests/vibrator/Android.bp
index 09608e9..3ebe150 100644
--- a/core/tests/vibrator/Android.bp
+++ b/core/tests/vibrator/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_haptics_framework",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["frameworks_base_license"],
 }
diff --git a/graphics/java/Android.bp b/graphics/java/Android.bp
index db37a387..ece453d 100644
--- a/graphics/java/Android.bp
+++ b/graphics/java/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_android_gpu",
     // 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"
diff --git a/graphics/java/android/graphics/pdf/TEST_MAPPING b/graphics/java/android/graphics/pdf/TEST_MAPPING
index d763598..afec35c 100644
--- a/graphics/java/android/graphics/pdf/TEST_MAPPING
+++ b/graphics/java/android/graphics/pdf/TEST_MAPPING
@@ -1,7 +1,12 @@
 {
   "presubmit": [
     {
-      "name": "CtsPdfTestCases"
+      "name": "CtsPdfTestCases",
+      "options": [
+        {
+          "include-filter": "android.graphics.pdf.cts.PdfDocumentTest"
+        }
+      ]
     }
   ]
 }
diff --git a/graphics/proto/Android.bp b/graphics/proto/Android.bp
index 1b19266..fdcfdd5 100644
--- a/graphics/proto/Android.bp
+++ b/graphics/proto/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_android_gpu",
     // 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"
diff --git a/libs/WindowManager/Shell/aconfig/OWNERS b/libs/WindowManager/Shell/aconfig/OWNERS
new file mode 100644
index 0000000..9eba0f2
--- /dev/null
+++ b/libs/WindowManager/Shell/aconfig/OWNERS
@@ -0,0 +1,3 @@
+# Owners for flag changes
+madym@google.com
+hwwang@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 9a66c0f..0967f4e 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -64,3 +64,10 @@
     description: "Enables the new bubble bar UI for tablets"
     bug: "286246694"
 }
+
+flag {
+    name: "enable_bubbles_long_press_nav_handle"
+    namespace: "multitasking"
+    description: "Enables long-press action for nav handle when a bubble is expanded"
+    bug: "324910035"
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 4e995bc..8946f41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -15,6 +15,7 @@
  */
 package com.android.wm.shell.bubbles.bar;
 
+import static android.view.View.ALPHA;
 import static android.view.View.SCALE_X;
 import static android.view.View.SCALE_Y;
 import static android.view.View.TRANSLATION_X;
@@ -69,6 +70,7 @@
     private static final float EXPANDED_VIEW_IN_TARGET_SCALE = 0.2f;
     private static final float EXPANDED_VIEW_DRAG_SCALE = 0.4f;
     private static final float DISMISS_VIEW_SCALE = 1.25f;
+    private static final int HANDLE_ALPHA_ANIMATION_DURATION = 100;
 
     /** Spring config for the expanded view scale-in animation. */
     private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
@@ -248,15 +250,22 @@
             return;
         }
         setDragPivot(bbev);
-        AnimatorSet animatorSet = new AnimatorSet();
         // Corner radius gets scaled, apply the reverse scale to ensure we have the desired radius
         final float cornerRadius = bbev.getDraggedCornerRadius() / EXPANDED_VIEW_DRAG_SCALE;
-        animatorSet.playTogether(
+
+        AnimatorSet contentAnim = new AnimatorSet();
+        contentAnim.playTogether(
                 ObjectAnimator.ofFloat(bbev, SCALE_X, EXPANDED_VIEW_DRAG_SCALE),
                 ObjectAnimator.ofFloat(bbev, SCALE_Y, EXPANDED_VIEW_DRAG_SCALE),
                 ObjectAnimator.ofFloat(bbev, CORNER_RADIUS, cornerRadius)
         );
-        animatorSet.setDuration(EXPANDED_VIEW_DRAG_ANIMATION_DURATION).setInterpolator(EMPHASIZED);
+        contentAnim.setDuration(EXPANDED_VIEW_DRAG_ANIMATION_DURATION).setInterpolator(EMPHASIZED);
+
+        ObjectAnimator handleAnim = ObjectAnimator.ofFloat(bbev.getHandleView(), ALPHA, 0f)
+                .setDuration(HANDLE_ALPHA_ANIMATION_DURATION);
+
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(contentAnim, handleAnim);
         animatorSet.addListener(new DragAnimatorListenerAdapter(bbev));
         startNewDragAnimation(animatorSet);
     }
@@ -297,15 +306,21 @@
         }
         Point restPoint = getExpandedViewRestPosition(getExpandedViewSize());
 
-        AnimatorSet animatorSet = new AnimatorSet();
-        animatorSet.playTogether(
+        AnimatorSet contentAnim = new AnimatorSet();
+        contentAnim.playTogether(
                 ObjectAnimator.ofFloat(bbev, X, restPoint.x),
                 ObjectAnimator.ofFloat(bbev, Y, restPoint.y),
                 ObjectAnimator.ofFloat(bbev, SCALE_X, 1f),
                 ObjectAnimator.ofFloat(bbev, SCALE_Y, 1f),
                 ObjectAnimator.ofFloat(bbev, CORNER_RADIUS, bbev.getRestingCornerRadius())
         );
-        animatorSet.setDuration(EXPANDED_VIEW_ANIMATE_TO_REST_DURATION).setInterpolator(EMPHASIZED);
+        contentAnim.setDuration(EXPANDED_VIEW_ANIMATE_TO_REST_DURATION).setInterpolator(EMPHASIZED);
+
+        ObjectAnimator handleAlphaAnim = ObjectAnimator.ofFloat(bbev.getHandleView(), ALPHA, 1f)
+                .setDuration(HANDLE_ALPHA_ANIMATION_DURATION);
+
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(contentAnim, handleAlphaAnim);
         animatorSet.addListener(new DragAnimatorListenerAdapter(bbev) {
             @Override
             public void onAnimationEnd(Animator animation) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index 81d1399..7c28099 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.AppCompatTaskInfo;
 import android.app.TaskInfo;
 import android.content.Context;
 import android.content.Intent;
@@ -88,7 +89,8 @@
         mShellExecutor = shellExecutor;
         mUserAspectRatioButtonShownChecker = userAspectRatioButtonStateChecker;
         mUserAspectRatioButtonStateConsumer = userAspectRatioButtonShownConsumer;
-        mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
+        mHasUserAspectRatioSettingsButton = shouldShowUserAspectRatioSettingsButton(
+                taskInfo.appCompatTaskInfo, taskInfo.baseIntent);
         mCompatUIHintsState = compatUIHintsState;
         mOnButtonClicked = onButtonClicked;
         mDisappearTimeSupplier = disappearTimeSupplier;
@@ -134,7 +136,8 @@
     public boolean updateCompatInfo(@NonNull TaskInfo taskInfo,
             @NonNull ShellTaskOrganizer.TaskListener taskListener, boolean canShow) {
         final boolean prevHasUserAspectRatioSettingsButton = mHasUserAspectRatioSettingsButton;
-        mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
+        mHasUserAspectRatioSettingsButton = shouldShowUserAspectRatioSettingsButton(
+                taskInfo.appCompatTaskInfo, taskInfo.baseIntent);
 
         if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
             return false;
@@ -227,12 +230,21 @@
         return SystemClock.uptimeMillis() + hideDelay;
     }
 
-    private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
-        final Intent intent = taskInfo.baseIntent;
-        return taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton
-                && (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
-                    || taskInfo.appCompatTaskInfo.isUserFullscreenOverrideEnabled)
-                && !taskInfo.appCompatTaskInfo.isSystemFullscreenOverrideEnabled
+    private boolean shouldShowUserAspectRatioSettingsButton(@NonNull AppCompatTaskInfo taskInfo,
+            @NonNull Intent intent) {
+        final Rect stableBounds = getTaskStableBounds();
+        final int letterboxHeight = taskInfo.topActivityLetterboxHeight;
+        final int letterboxWidth = taskInfo.topActivityLetterboxWidth;
+        // App is not visibly letterboxed if it covers status bar/bottom insets or matches the
+        // stable bounds, so don't show the button
+        if (stableBounds.height() <= letterboxHeight && stableBounds.width() <= letterboxWidth) {
+            return false;
+        }
+
+        return taskInfo.topActivityEligibleForUserAspectRatioButton
+                && (taskInfo.topActivityBoundsLetterboxed
+                    || taskInfo.isUserFullscreenOverrideEnabled)
+                && !taskInfo.isSystemFullscreenOverrideEnabled
                 && Intent.ACTION_MAIN.equals(intent.getAction())
                 && intent.hasCategory(Intent.CATEGORY_LAUNCHER)
                 && (!mUserAspectRatioButtonShownChecker.get() || isShowingButton());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index e732a03..8305fa6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -47,4 +47,8 @@
     default void addDesktopGestureExclusionRegionListener(Consumer<Region> listener,
             Executor callbackExecutor) { }
 
+
+    /** Called when requested to go to desktop mode from the current focused app. */
+    void enterDesktop(int displayId);
+
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 11304ec..6de5d74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -21,6 +21,7 @@
 import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
 import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
 import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
 import android.app.WindowConfiguration.WindowingMode
 import android.content.Context
@@ -240,6 +241,43 @@
         return desktopModeTaskRepository.getVisibleTaskCount(displayId)
     }
 
+    /** Enter desktop by using the focused task in given `displayId` */
+    fun enterDesktop(displayId: Int) {
+        val allFocusedTasks =
+            shellTaskOrganizer.getRunningTasks(displayId).filter { taskInfo ->
+                taskInfo.isFocused &&
+                        (taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN ||
+                                taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW) &&
+                        taskInfo.activityType != ACTIVITY_TYPE_HOME
+            }
+        if (allFocusedTasks.isNotEmpty()) {
+            when (allFocusedTasks.size) {
+                2 -> {
+                    // Split-screen case where there are two focused tasks, then we find the child
+                    // task to move to desktop.
+                    val splitFocusedTask = findChildFocusedTask(allFocusedTasks)
+                    moveToDesktop(splitFocusedTask)
+                }
+                1 -> {
+                    // Fullscreen case where we move the current focused task.
+                    moveToDesktop(allFocusedTasks[0].taskId)
+                }
+                else -> {
+                    KtProtoLog.v(
+                        WM_SHELL_DESKTOP_MODE,
+                        "DesktopTasksController: Cannot enter desktop expected less " +
+                                "than 3 focused tasks but found " + allFocusedTasks.size
+                    )
+                }
+            }
+        }
+    }
+
+    private fun findChildFocusedTask(allFocusedTasks: List<RunningTaskInfo>): RunningTaskInfo {
+        if (allFocusedTasks[0].taskId == allFocusedTasks[1].parentTaskId) return allFocusedTasks[1]
+        return allFocusedTasks[0]
+    }
+
     /** Move a task with given `taskId` to desktop */
     fun moveToDesktop(
             taskId: Int,
@@ -1012,6 +1050,12 @@
                 this@DesktopTasksController.setTaskRegionListener(listener, callbackExecutor)
             }
         }
+
+        override fun enterDesktop(displayId: Int) {
+            mainExecutor.execute {
+                this@DesktopTasksController.enterDesktop(displayId)
+            }
+        }
     }
 
     /** The interface for calls from outside the host process. */
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index f3145c9..e6a2022 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -113,7 +113,6 @@
                             subject.name.contains(primaryApp.toLayerName()) && subject.isVisible
                         }
                         .mapNotNull { primaryApp -> primaryApp.layer.visibleRegion }
-                        .toTypedArray()
 
                 val primaryAppRegionArea = RegionSubject(primaryAppRegions, it.timestamp)
                 it.visibleRegion(secondaryApp).notOverlaps(primaryAppRegionArea.region)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
index 9fe2cb1..81ba4b3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
@@ -113,8 +113,22 @@
         mExecutor = new TestShellExecutor();
         mTaskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
                 false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
+        final DisplayInfo displayInfo = new DisplayInfo();
+        final int displayWidth = 1000;
+        final int displayHeight = 1200;
+        displayInfo.logicalWidth = displayWidth;
+        displayInfo.logicalHeight = displayHeight;
+        final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
+                mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
+        InsetsState insetsState = new InsetsState();
+        insetsState.setDisplayFrame(new Rect(0, 0, displayWidth, displayHeight));
+        InsetsSource insetsSource = new InsetsSource(
+                InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+        insetsSource.setFrame(0, displayHeight - 200, displayWidth, displayHeight);
+        insetsState.addSource(insetsSource);
+        displayLayout.setInsets(mContext.getResources(), insetsState);
         mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
-                mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
+                mSyncTransactionQueue, mTaskListener, displayLayout, new CompatUIHintsState(),
                 mOnUserAspectRatioSettingsButtonClicked, mExecutor, flags -> 0,
                 mUserAspectRatioButtonShownChecker, s -> {});
         spyOn(mWindowManager);
@@ -253,6 +267,31 @@
     }
 
     @Test
+    public void testEligibleButtonHiddenIfLetterboxBoundsEqualToStableBounds() {
+        TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+                true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
+
+        final Rect stableBounds = mWindowManager.getTaskStableBounds();
+        final int stableHeight = stableBounds.height();
+
+        // Letterboxed activity bounds equal to stable bounds, layout shouldn't be inflated
+        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = stableHeight;
+        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = stableBounds.width();
+
+        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+
+        verify(mWindowManager, never()).inflateLayout();
+
+        // Letterboxed activity bounds smaller than stable bounds, layout should be inflated
+        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = stableHeight - 100;
+
+        clearInvocations(mWindowManager);
+        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+
+        verify(mWindowManager).inflateLayout();
+    }
+
+    @Test
     public void testUpdateDisplayLayout() {
         final DisplayInfo displayInfo = new DisplayInfo();
         displayInfo.logicalWidth = 1000;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 63618f4..cb64c52 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -734,6 +734,46 @@
         shellExecutor.flushAll()
         verify(launchAdjacentController).launchAdjacentEnabled = true
     }
+    @Test
+    fun enterDesktop_fullscreenTaskIsMovedToDesktop() {
+        val task1 = setUpFullscreenTask()
+        val task2 = setUpFullscreenTask()
+        val task3 = setUpFullscreenTask()
+
+        task1.isFocused = true
+        task2.isFocused = false
+        task3.isFocused = false
+
+        controller.enterDesktop(DEFAULT_DISPLAY)
+
+        val wct = getLatestMoveToDesktopWct()
+        assertThat(wct.changes[task1.token.asBinder()]?.windowingMode)
+                .isEqualTo(WINDOWING_MODE_FREEFORM)
+    }
+
+    @Test
+    fun enterDesktop_splitScreenTaskIsMovedToDesktop() {
+        val task1 = setUpSplitScreenTask()
+        val task2 = setUpFullscreenTask()
+        val task3 = setUpFullscreenTask()
+        val task4 = setUpSplitScreenTask()
+
+        task1.isFocused = true
+        task2.isFocused = false
+        task3.isFocused = false
+        task4.isFocused = true
+
+        task4.parentTaskId = task1.taskId
+
+        controller.enterDesktop(DEFAULT_DISPLAY)
+
+        val wct = getLatestMoveToDesktopWct()
+        assertThat(wct.changes[task4.token.asBinder()]?.windowingMode)
+                .isEqualTo(WINDOWING_MODE_FREEFORM)
+        verify(splitScreenController).prepareExitSplitScreen(any(), anyInt(),
+            eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE)
+        )
+    }
 
     private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
         val task = createFreeformTask(displayId)
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 8748dab..46f636e 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -117,6 +117,10 @@
   return true;
 }
 
+void AssetManager2::PresetApkAssets(ApkAssetsList apk_assets) {
+  BuildDynamicRefTable(apk_assets);
+}
+
 bool AssetManager2::SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets,
                                  bool invalidate_caches) {
   return SetApkAssets(ApkAssetsList(apk_assets.begin(), apk_assets.size()), invalidate_caches);
@@ -432,13 +436,18 @@
   return false;
 }
 
-void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations) {
+void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations,
+    bool force_refresh) {
   int diff = 0;
-  if (configurations_.size() != configurations.size()) {
+  if (force_refresh) {
     diff = -1;
   } else {
-    for (int i = 0; i < configurations_.size(); i++) {
-      diff |= configurations_[i].diff(configurations[i]);
+    if (configurations_.size() != configurations.size()) {
+      diff = -1;
+    } else {
+      for (int i = 0; i < configurations_.size(); i++) {
+        diff |= configurations_[i].diff(configurations[i]);
+      }
     }
   }
   configurations_ = std::move(configurations);
@@ -775,8 +784,7 @@
     bool has_locale = false;
     if (result->config.locale == 0) {
       if (default_locale_ != 0) {
-        ResTable_config conf;
-        conf.locale = default_locale_;
+        ResTable_config conf = {.locale = default_locale_};
         // Since we know conf has a locale and only a locale, match will tell us if that locale
         // matches
         has_locale = conf.match(config);
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index d9ff35b..17a8ba6 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -124,6 +124,9 @@
   // new resource IDs.
   bool SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches = true);
   bool SetApkAssets(std::initializer_list<ApkAssetsPtr> apk_assets, bool invalidate_caches = true);
+  // This one is an optimization - it skips all calculations for applying the currently set
+  // configuration, expecting a configuration update later with a forced refresh.
+  void PresetApkAssets(ApkAssetsList apk_assets);
 
   const ApkAssetsPtr& GetApkAssets(ApkAssetsCookie cookie) const;
   int GetApkAssetsCount() const {
@@ -156,7 +159,7 @@
 
   // Sets/resets the configuration for this AssetManager. This will cause all
   // caches that are related to the configuration change to be invalidated.
-  void SetConfigurations(std::vector<ResTable_config> configurations);
+  void SetConfigurations(std::vector<ResTable_config> configurations, bool force_refresh = false);
 
   inline const std::vector<ResTable_config>& GetConfigurations() const {
     return configurations_;
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 71f7926..27ea150 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -378,10 +378,17 @@
             break;
         case kAlpha_8_SkColorType:
             formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
-            formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
-            formatInfo.format = GL_RED;
-            formatInfo.type = GL_UNSIGNED_BYTE;
-            formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+            if (formatInfo.isSupported) {
+                formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+                formatInfo.format = GL_RED;
+                formatInfo.type = GL_UNSIGNED_BYTE;
+                formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+            } else {
+                formatInfo.type = GL_UNSIGNED_BYTE;
+                formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+                formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
+                formatInfo.format = GL_RGBA;
+            }
             break;
         default:
             ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 8344a86..1854361 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -147,11 +147,7 @@
 }
 
 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
-    if (bitmap.colorType() == kAlpha_8_SkColorType &&
-        !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
-        return nullptr;
-    }
+#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
     return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
 #else
     return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 2795cfe..f05ea9c 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -336,8 +336,9 @@
      * This method must not be called when the Visualizer is enabled.
      * @param size requested capture size
      * @return {@link #SUCCESS} in case of success,
-     * {@link #ERROR_BAD_VALUE} in case of failure.
-     * @throws IllegalStateException
+     * {@link #ERROR_INVALID_OPERATION} if Visualizer effect enginer not enabled.
+     * @throws IllegalStateException if the effect is not in proper state.
+     * @throws IllegalArgumentException if the size parameter is invalid (out of supported range).
      */
     public int setCaptureSize(int size)
     throws IllegalStateException {
@@ -345,7 +346,13 @@
             if (mState != STATE_INITIALIZED) {
                 throw(new IllegalStateException("setCaptureSize() called in wrong state: "+mState));
             }
-            return native_setCaptureSize(size);
+
+            int ret = native_setCaptureSize(size);
+            if (ret == ERROR_BAD_VALUE) {
+                throw(new IllegalArgumentException("setCaptureSize to " + size + " failed"));
+            }
+
+            return ret;
         }
     }
 
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index e92c7b3..d17b341 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -107,11 +107,15 @@
 
     private final ServiceState mServiceState = new ServiceState();
 
+    // Holds the connection record associated with the currently executing callback operation, if
+    // any. See getCurrentBrowserInfo for an example. Must only be accessed on mHandler.
+    @Nullable private ConnectionRecord mCurrentConnectionOnHandler;
+
     /**
      * All the info about a connection.
      */
     private static class ConnectionRecord implements IBinder.DeathRecipient {
-        public final MediaBrowserService service;
+        public final ServiceState serviceState;
         public final String pkg;
         public final int pid;
         public final int uid;
@@ -121,9 +125,14 @@
         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;
+                ServiceState serviceState,
+                String pkg,
+                int pid,
+                int uid,
+                Bundle rootHints,
+                IMediaBrowserServiceCallbacks callbacks,
+                BrowserRoot root) {
+            this.serviceState = serviceState;
             this.pkg = pkg;
             this.pid = pid;
             this.uid = uid;
@@ -134,12 +143,8 @@
 
         @Override
         public void binderDied() {
-            service.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    service.mServiceState.mConnections.remove(callbacks.asBinder());
-                }
-            });
+            serviceState.postOnHandler(
+                    () -> serviceState.mConnections.remove(callbacks.asBinder()));
         }
     }
 
@@ -461,12 +466,12 @@
      * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
      */
     public final Bundle getBrowserRootHints() {
-        ConnectionRecord curConnection = mServiceState.mCurConnection;
-        if (curConnection == null) {
+        ConnectionRecord currentConnection = mCurrentConnectionOnHandler;
+        if (currentConnection == null) {
             throw new IllegalStateException("This should be called inside of onGetRoot or"
                     + " onLoadChildren or onLoadItem methods");
         }
-        return curConnection.rootHints == null ? null : new Bundle(curConnection.rootHints);
+        return currentConnection.rootHints == null ? null : new Bundle(currentConnection.rootHints);
     }
 
     /**
@@ -477,12 +482,13 @@
      * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
      */
     public final RemoteUserInfo getCurrentBrowserInfo() {
-        ConnectionRecord curConnection = mServiceState.mCurConnection;
-        if (curConnection == null) {
+        ConnectionRecord currentConnection = mCurrentConnectionOnHandler;
+        if (currentConnection == null) {
             throw new IllegalStateException("This should be called inside of onGetRoot or"
                     + " onLoadChildren or onLoadItem methods");
         }
-        return new RemoteUserInfo(curConnection.pkg, curConnection.pid, curConnection.uid);
+        return new RemoteUserInfo(
+                currentConnection.pkg, currentConnection.pid, currentConnection.uid);
     }
 
     /**
@@ -621,7 +627,6 @@
 
         // Fields accessed from mHandler only.
         @NonNull private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
-        @Nullable private ConnectionRecord mCurConnection;
 
         public void postOnHandler(Runnable runnable) {
             mHandler.post(runnable);
@@ -704,9 +709,9 @@
 
             // Temporarily sets a placeholder ConnectionRecord to make getCurrentBrowserInfo() work
             // in onGetRoot().
-            mCurConnection =
+            mCurrentConnectionOnHandler =
                     new ConnectionRecord(
-                            /* service= */ MediaBrowserService.this,
+                            /* serviceState= */ this,
                             pkg,
                             pid,
                             uid,
@@ -714,7 +719,7 @@
                             callbacks,
                             /* root= */ null);
             BrowserRoot root = onGetRoot(pkg, uid, rootHints);
-            mCurConnection = null;
+            mCurrentConnectionOnHandler = null;
 
             // If they didn't return something, don't allow this client.
             if (root == null) {
@@ -728,7 +733,7 @@
                 try {
                     ConnectionRecord connection =
                             new ConnectionRecord(
-                                    /* service= */ MediaBrowserService.this,
+                                    /* serviceState= */ this,
                                     pkg,
                                     pid,
                                     uid,
@@ -830,13 +835,13 @@
                         }
                     };
 
-            mCurConnection = connection;
+            mCurrentConnectionOnHandler = connection;
             if (options == null) {
                 onLoadChildren(parentId, result);
             } else {
                 onLoadChildren(parentId, result, options);
             }
-            mCurConnection = null;
+            mCurrentConnectionOnHandler = null;
 
             if (!result.isDone()) {
                 throw new IllegalStateException(
@@ -885,9 +890,9 @@
                         }
                     };
 
-            mCurConnection = connection;
+            mCurrentConnectionOnHandler = connection;
             onLoadItem(itemId, result);
-            mCurConnection = null;
+            mCurrentConnectionOnHandler = null;
 
             if (!result.isDone()) {
                 throw new IllegalStateException(
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index 09c45ea..9ae5c99 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -25,7 +25,6 @@
 #include <limits.h>
 
 #include <audio_utils/fixedfft.h>
-#include <cutils/bitops.h>
 #include <utils/Thread.h>
 
 #include <android/content/AttributionSourceState.h>
@@ -59,8 +58,8 @@
     status_t status = AudioEffect::set(
             SL_IID_VISUALIZATION, nullptr, priority, cbf, user, sessionId, io, device, probe);
     if (status == NO_ERROR || status == ALREADY_EXISTS) {
-        initCaptureSize();
-        initSampleRate();
+        status = initCaptureSize();
+        if (status == NO_ERROR) initSampleRate();
     }
     return status;
 }
@@ -152,9 +151,8 @@
 
 status_t Visualizer::setCaptureSize(uint32_t size)
 {
-    if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
-        size < VISUALIZER_CAPTURE_SIZE_MIN ||
-        popcount(size) != 1) {
+    if (!isCaptureSizeValid(size)) {
+        ALOGE("%s with invalid capture size %u from HAL", __func__, size);
         return BAD_VALUE;
     }
 
@@ -172,7 +170,7 @@
     *((int32_t *)p->data + 1)= size;
     status_t status = setParameter(p);
 
-    ALOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
+    ALOGV("setCaptureSize size %u status %d p->status %d", size, status, p->status);
 
     if (status == NO_ERROR) {
         status = p->status;
@@ -257,8 +255,8 @@
     if ((type != MEASUREMENT_MODE_PEAK_RMS)
             // for peak+RMS measurement, the results are 2 int32_t values
             || (number != 2)) {
-        ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
-                        number);
+        ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %u",
+              number);
         return BAD_VALUE;
     }
 
@@ -390,7 +388,7 @@
     }
 }
 
-uint32_t Visualizer::initCaptureSize()
+status_t Visualizer::initCaptureSize()
 {
     uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
     effect_param_t *p = (effect_param_t *)buf32;
@@ -405,14 +403,20 @@
     }
 
     uint32_t size = 0;
-    if (status == NO_ERROR) {
-        size = *((int32_t *)p->data + 1);
+    if (status != NO_ERROR) {
+        ALOGE("%s getParameter failed status %d", __func__, status);
+        return status;
     }
+
+    size = *((int32_t *)p->data + 1);
+    if (!isCaptureSizeValid(size)) {
+        ALOGE("%s with invalid capture size %u from HAL", __func__, size);
+        return BAD_VALUE;
+    }
+
     mCaptureSize = size;
-
-    ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
-
-    return size;
+    ALOGV("%s size %u status %d", __func__, mCaptureSize, status);
+    return NO_ERROR;
 }
 
 void Visualizer::initSampleRate()
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index b38c01f..26d58d0 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -20,6 +20,8 @@
 #include <media/AudioEffect.h>
 #include <system/audio_effects/effect_visualizer.h>
 #include <utils/Thread.h>
+#include <cstdint>
+#include <cutils/bitops.h>
 #include "android/content/AttributionSourceState.h"
 
 /**
@@ -170,8 +172,12 @@
 
     status_t doFft(uint8_t *fft, uint8_t *waveform);
     void periodicCapture();
-    uint32_t initCaptureSize();
+    status_t initCaptureSize();
     void initSampleRate();
+    static constexpr bool isCaptureSizeValid(uint32_t size) {
+        return size <= VISUALIZER_CAPTURE_SIZE_MAX && size >= VISUALIZER_CAPTURE_SIZE_MIN &&
+                popcount(size) == 1;
+    }
 
     Mutex mCaptureLock;
     uint32_t mCaptureRate = CAPTURE_RATE_DEF;
diff --git a/media/tests/mediatestutils/Android.bp b/media/tests/mediatestutils/Android.bp
index 15bc177..88938e2 100644
--- a/media/tests/mediatestutils/Android.bp
+++ b/media/tests/mediatestutils/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_media_framework_audio",
     // 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"
diff --git a/media/tests/mediatestutils/tests/Android.bp b/media/tests/mediatestutils/tests/Android.bp
index 24a8360..f586f97f 100644
--- a/media/tests/mediatestutils/tests/Android.bp
+++ b/media/tests/mediatestutils/tests/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_media_framework_audio",
     // 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"
diff --git a/nfc-extras/Android.bp b/nfc-extras/Android.bp
index 1f187e8..699ad50 100644
--- a/nfc-extras/Android.bp
+++ b/nfc-extras/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_fwk_nfc",
     // 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"
@@ -28,7 +29,7 @@
     name: "com.android.nfc_extras",
     srcs: ["java/**/*.java"],
     libs: [
-        "framework-nfc.impl"
+        "framework-nfc.impl",
     ],
     api_packages: ["com.android.nfc_extras"],
     dist_group: "android",
diff --git a/nfc-extras/tests/Android.bp b/nfc-extras/tests/Android.bp
index 4c1f2fb..e8214b0 100644
--- a/nfc-extras/tests/Android.bp
+++ b/nfc-extras/tests/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_fwk_nfc",
     // 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"
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 7136866..b6bc40d 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_fwk_nfc",
     // 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"
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 845a8f9..f111327 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -206,9 +206,9 @@
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean removeAidsForService(android.content.ComponentName, String);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
-    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setServiceObserveModeDefault(@NonNull android.content.ComponentName, boolean);
     method public boolean supportsAidPrefixRegistration();
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 791bd8c..65d0625 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -30,7 +30,7 @@
     boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
     boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
     boolean setDefaultForNextTap(int userHandle, in ComponentName service);
-    boolean setServiceObserveModeDefault(int userId, in android.content.ComponentName service, boolean enable);
+    boolean setDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
     boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
     boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter);
     boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index f264b16..32dba5f 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -105,7 +105,6 @@
      */
     private final HashMap<String, AidGroup> mDynamicAidGroups;
 
-    private final ArrayList<String> mPollingLoopFilters;
 
     private final Map<String, Boolean> mAutoTransact;
 
@@ -181,7 +180,6 @@
         this.mDescription = description;
         this.mStaticAidGroups = new HashMap<String, AidGroup>();
         this.mDynamicAidGroups = new HashMap<String, AidGroup>();
-        this.mPollingLoopFilters = new ArrayList<String>();
         this.mAutoTransact = new HashMap<String, Boolean>();
         this.mOffHostName = offHost;
         this.mStaticOffHostName = staticOffHost;
@@ -302,7 +300,6 @@
 
             mStaticAidGroups = new HashMap<String, AidGroup>();
             mDynamicAidGroups = new HashMap<String, AidGroup>();
-            mPollingLoopFilters = new ArrayList<String>();
             mAutoTransact = new HashMap<String, Boolean>();
             mOnHost = onHost;
 
@@ -393,7 +390,6 @@
                     String plf =
                             a.getString(com.android.internal.R.styleable.PollingLoopFilter_name)
                             .toUpperCase(Locale.ROOT);
-                    mPollingLoopFilters.add(plf);
                     boolean autoTransact = a.getBoolean(
                             com.android.internal.R.styleable.PollingLoopFilter_autoTransact,
                             false);
@@ -461,7 +457,7 @@
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     @NonNull
     public List<String> getPollingLoopFilters() {
-        return mPollingLoopFilters;
+        return new ArrayList<>(mAutoTransact.keySet());
     }
 
     /**
@@ -672,12 +668,15 @@
 
     /**
      * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will be
-     * delivered to {@link HostApduService#processPollingFrames(List)}.
-     * @param pollingLoopFilter this polling loop filter to add.
+     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this or
+     * {@link  ApduServiceInfo#addPollingLoopFilterToAutoTransact(String)} multiple times will
+     * cause the value to be overwritten each time.
+     * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void addPollingLoopFilter(@NonNull String pollingLoopFilter) {
-        mPollingLoopFilters.add(pollingLoopFilter.toUpperCase(Locale.ROOT));
+        mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), false);
+
     }
 
     /**
@@ -685,13 +684,14 @@
      * device to exit observe mode, just as if
      * {@link android.nfc.NfcAdapter#setTransactionAllowed(boolean)} had been called with true,
      * allowing transactions to proceed. The matching frame will also be delivered to
-     * {@link HostApduService#processPollingFrames(List)}.
+     * {@link HostApduService#processPollingFrames(List)}. Adding a key with this or
+     * {@link  ApduServiceInfo#addPollingLoopFilter(String)} multiple times will
+     * cause the value to be overwritten each time.
      *
-     * @param pollingLoopFilter this polling loop filter to add.
+     * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void addPollingLoopFilterToAutoTransact(@NonNull String pollingLoopFilter) {
-        mPollingLoopFilters.add(pollingLoopFilter.toUpperCase(Locale.ROOT));
         mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), true);
     }
 
@@ -702,7 +702,7 @@
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void removePollingLoopFilter(@NonNull String pollingLoopFilter) {
-        mPollingLoopFilters.remove(pollingLoopFilter.toUpperCase(Locale.ROOT));
+        mAutoTransact.remove(pollingLoopFilter.toUpperCase(Locale.ROOT));
     }
 
     /**
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 1f41b81..e681a85 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -338,19 +338,20 @@
         }
     }
     /**
-     * Sets whether the system should default to observe mode or not when the service is in the
-     * foreground or the default payment service. The default is to not enable observe mode when
-     * a service either the foreground default service or the default payment service so not
-     * calling this method will preserve that behavior.
+     * Sets whether when this service becomes the preferred service, if the NFC stack
+     * should enable observe mode or disable observe mode. The default is to not enable observe
+     * mode when a service either the foreground default service or the default payment service so
+     * not calling this method will preserve that behavior.
      *
      * @param service The component name of the service
-     * @param enable Whether the servic should default to observe mode or not
+     * @param enable Whether the service should default to observe mode or not
      * @return whether the change was successful.
      */
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
-    public boolean setServiceObserveModeDefault(@NonNull ComponentName service, boolean enable) {
+    public boolean setDefaultToObserveModeForService(@NonNull ComponentName service,
+            boolean enable) {
         try {
-            return sService.setServiceObserveModeDefault(mContext.getUser().getIdentifier(),
+            return sService.setDefaultToObserveModeForService(mContext.getUser().getIdentifier(),
                     service, enable);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to reach CardEmulationService.");
@@ -359,9 +360,14 @@
     }
 
     /**
-     * Register a polling loop filter for a HostApduService.
-     * @param service The HostApduService to register the filter for.
-     * @param pollingLoopFilter The filter to register.
+     * Register a polling loop filter (PLF) for a HostApduService. The PLF can be sequence of an
+     * even number of hexadecimal numbers (0-9, A-F or a-f). When non-standard polling loop frame
+     * matches this sequence exactly, it may be delivered to
+     * {@link HostApduService#processPollingFrames(List)}  if this service is currently
+     * preferred or there are no other services registered for this filter.
+     * @param service The HostApduService to register the filter for
+     * @param pollingLoopFilter The filter to register
+     * @return true if the filter was registered, false otherwise
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public boolean registerPollingLoopFilterForService(@NonNull ComponentName service,
diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
index 89b0322..363788e 100644
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
@@ -470,7 +470,7 @@
     }
 
     /**
-     * This method is called when a polling frame has been received from a
+     * This method is called when polling frames have been received from a
      * remote device. If the device is in observe mode, the service should
      * call {@link NfcAdapter#allowTransaction()} once it is ready to proceed
      * with the transaction. If the device is not in observe mode, the service
diff --git a/nfc/tests/Android.bp b/nfc/tests/Android.bp
index 62566ee..6ebc03c 100644
--- a/nfc/tests/Android.bp
+++ b/nfc/tests/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_fwk_nfc",
     // 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"
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index b5951e8..9217e70 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -75,6 +75,8 @@
  */
 public class RescueParty {
     @VisibleForTesting
+    static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
+    @VisibleForTesting
     static final int LEVEL_NONE = 0;
     @VisibleForTesting
     static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
@@ -123,7 +125,7 @@
 
     private static boolean isDisabled() {
         // Check if we're explicitly enabled for testing
-        if (CrashRecoveryProperties.enableRescueParty().orElse(false)) {
+        if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
             return false;
         }
 
@@ -176,6 +178,29 @@
         return CrashRecoveryProperties.attemptingReboot().orElse(false);
     }
 
+    protected static long getLastFactoryResetTimeMs() {
+        return CrashRecoveryProperties.lastFactoryResetTimeMs().orElse(0L);
+    }
+
+    protected static int getMaxRescueLevelAttempted() {
+        return CrashRecoveryProperties.maxRescueLevelAttempted().orElse(LEVEL_NONE);
+    }
+
+    protected static void setFactoryResetProperty(boolean value) {
+        CrashRecoveryProperties.attemptingFactoryReset(value);
+    }
+    protected static void setRebootProperty(boolean value) {
+        CrashRecoveryProperties.attemptingReboot(value);
+    }
+
+    protected static void setLastFactoryResetTimeMs(long value) {
+        CrashRecoveryProperties.lastFactoryResetTimeMs(value);
+    }
+
+    protected static void setMaxRescueLevelAttempted(int level) {
+        CrashRecoveryProperties.maxRescueLevelAttempted(level);
+    }
+
     /**
      * Called when {@code SettingsProvider} has been published, which is a good
      * opportunity to reset any settings depending on our rescue level.
@@ -432,7 +457,7 @@
             case LEVEL_WARM_REBOOT:
                 // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
                 // when device shutting down.
-                CrashRecoveryProperties.attemptingReboot(true);
+                setRebootProperty(true);
                 runnable = () -> {
                     try {
                         PowerManager pm = context.getSystemService(PowerManager.class);
@@ -454,9 +479,9 @@
                 if (isRebootPropertySet()) {
                     break;
                 }
-                CrashRecoveryProperties.attemptingFactoryReset(true);
+                setFactoryResetProperty(true);
                 long now = System.currentTimeMillis();
-                CrashRecoveryProperties.lastFactoryResetTimeMs(now);
+                setLastFactoryResetTimeMs(now);
                 runnable = new Runnable() {
                     @Override
                     public void run() {
@@ -515,10 +540,10 @@
     private static void resetAllSettingsIfNecessary(Context context, int mode,
             int level) throws Exception {
         // No need to reset Settings again if they are already reset in the current level once.
-        if (CrashRecoveryProperties.maxRescueLevelAttempted().orElse(LEVEL_NONE) >= level) {
+        if (getMaxRescueLevelAttempted() >= level) {
             return;
         }
-        CrashRecoveryProperties.maxRescueLevelAttempted(level);
+        setMaxRescueLevelAttempted(level);
         // Try our best to reset all settings possible, and once finished
         // rethrow any exception that we encountered
         Exception res = null;
@@ -733,7 +758,7 @@
          * Will return {@code false} if a factory reset was already offered recently.
          */
         private boolean shouldThrottleReboot() {
-            Long lastResetTime = CrashRecoveryProperties.lastFactoryResetTimeMs().orElse(0L);
+            Long lastResetTime = getLastFactoryResetTimeMs();
             long now = System.currentTimeMillis();
             long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
                     DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
index 98a5a67..b646da4 100644
--- a/packages/PackageInstaller/Android.bp
+++ b/packages/PackageInstaller/Android.bp
@@ -59,69 +59,5 @@
     lint: {
         error_checks: ["Recycle"],
     },
-}
-
-android_app {
-    name: "PackageInstaller_tablet",
-    defaults: ["platform_app_defaults"],
-
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-    ],
-
-    certificate: "platform",
-    privileged: true,
-    platform_apis: false,
-    sdk_version: "system_current",
-    rename_resources_package: false,
-    overrides: ["PackageInstaller"],
-
-    static_libs: [
-        "xz-java",
-        "androidx.leanback_leanback",
-        "androidx.fragment_fragment",
-        "androidx.lifecycle_lifecycle-livedata",
-        "androidx.lifecycle_lifecycle-extensions",
-        "android.content.pm.flags-aconfig-java",
-        "android.os.flags-aconfig-java",
-    ],
-    aaptflags: ["--product tablet"],
-
-    lint: {
-        error_checks: ["Recycle"],
-    },
-}
-
-android_app {
-    name: "PackageInstaller_tv",
-    defaults: ["platform_app_defaults"],
-
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-    ],
-
-    certificate: "platform",
-    privileged: true,
-    platform_apis: false,
-    sdk_version: "system_current",
-    rename_resources_package: false,
-    overrides: ["PackageInstaller"],
-
-    static_libs: [
-        "xz-java",
-        "androidx.leanback_leanback",
-        "androidx.annotation_annotation",
-        "androidx.fragment_fragment",
-        "androidx.lifecycle_lifecycle-livedata",
-        "androidx.lifecycle_lifecycle-extensions",
-        "android.content.pm.flags-aconfig-java",
-        "android.os.flags-aconfig-java",
-    ],
-    aaptflags: ["--product tv"],
-
-    lint: {
-        error_checks: ["Recycle"],
-    },
+    generate_product_characteristics_rro: true,
 }
diff --git a/packages/PackageInstaller/res/values-night/themes.xml b/packages/PackageInstaller/res/values-night/themes.xml
index 18320f7..a5b82b3 100644
--- a/packages/PackageInstaller/res/values-night/themes.xml
+++ b/packages/PackageInstaller/res/values-night/themes.xml
@@ -20,6 +20,9 @@
     <style name="Theme.AlertDialogActivity"
         parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
         <item name="alertDialogStyle">@style/AlertDialog</item>
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowAnimationStyle">@null</item>
     </style>
 
 </resources>
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
index ec519ca..463e9be 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -29,7 +29,7 @@
 
 allprojects {
     extra["androidTop"] = androidTop
-    extra["jetpackComposeVersion"] = "1.7.0-alpha01"
+    extra["jetpackComposeVersion"] = "1.7.0-alpha02"
 }
 
 subprojects {
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index f6fbc02..fe378c2 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -16,7 +16,7 @@
 
 [versions]
 agp = "8.2.2"
-compose-compiler = "1.5.8"
+compose-compiler = "1.5.9"
 dexmaker-mockito = "2.28.3"
 jvm = "17"
 kotlin = "1.9.22"
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 08a8797..2259bd74 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -57,13 +57,13 @@
     api("androidx.slice:slice-builders:1.1.0-alpha02")
     api("androidx.slice:slice-core:1.1.0-alpha02")
     api("androidx.slice:slice-view:1.1.0-alpha02")
-    api("androidx.compose.material3:material3:1.2.0-rc01")
+    api("androidx.compose.material3:material3:1.2.0")
     api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
     api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
     api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
     api("androidx.lifecycle:lifecycle-livedata-ktx")
     api("androidx.lifecycle:lifecycle-runtime-compose")
-    api("androidx.navigation:navigation-compose:2.8.0-alpha01")
+    api("androidx.navigation:navigation-compose:2.8.0-alpha02")
     api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha")
     api("com.google.android.material:material:1.7.0-alpha03")
     debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ListPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ListPreference.kt
index a0149da..1a04bb8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ListPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ListPreference.kt
@@ -37,11 +37,13 @@
 import androidx.compose.ui.semantics.Role
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.dialog.SettingsDialog
+import com.android.settingslib.spa.widget.ui.SettingsBody
 import com.android.settingslib.spa.widget.ui.SettingsDialogItem
 
 data class ListPreferenceOption(
     val id: Int,
     val text: String,
+    val summary: String = String()
 )
 
 /**
@@ -129,6 +131,14 @@
     ) {
         RadioButton(selected = selected, onClick = null, enabled = enabled)
         Spacer(modifier = Modifier.width(SettingsDimension.itemPaddingEnd))
-        SettingsDialogItem(text = option.text, enabled = enabled)
+        Column {
+            SettingsDialogItem(text = option.text, enabled = enabled)
+            if (option.summary != String()) {
+                SettingsBody(
+                    body = option.summary,
+                    maxLines = 1
+                )
+            }
+        }
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt
index e36572f..3216e37 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt
@@ -24,7 +24,6 @@
 import androidx.compose.foundation.layout.size
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
@@ -46,14 +45,14 @@
         verticalAlignment = Alignment.CenterVertically,
     ) {
         Box(modifier = Modifier.weight(1f)) {
-            Preference(remember {
+            Preference(
                 object : PreferenceModel {
                     override val title = title
                     override val summary = summary
                     override val icon = icon
                     override val onClick = onClick
                 }
-            })
+            )
         }
         PreferenceDivider()
         widget()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ListPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ListPreferenceTest.kt
index 796ac48..417ce6e 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ListPreferenceTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ListPreferenceTest.kt
@@ -123,6 +123,26 @@
     }
 
     @Test
+    fun click_optionsNotEmptyAndItemHasSummary_itemShowSummary() {
+        composeTestRule.setContent {
+            ListPreference(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val options =
+                        listOf(ListPreferenceOption(id = 1, text = "A", summary = "A_Summary"))
+                    override val selectedId = mutableIntStateOf(1)
+                    override val onIdSelected: (Int) -> Unit = {}
+                }
+            })
+        }
+
+        composeTestRule.onNodeWithText(TITLE).performClick()
+
+        composeTestRule.onDialogText(TITLE).assertIsDisplayed()
+        composeTestRule.onNodeWithText("A_Summary").assertIsDisplayed()
+    }
+
+    @Test
     fun select() {
         val selectedId = mutableIntStateOf(1)
         composeTestRule.setContent {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1092a16..9588e50 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1129,7 +1129,7 @@
     <!-- [CHAR_LIMIT=80] Label for battery level chart when charge been limited -->
     <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Charging optimized</string>
     <!-- [CHAR_LIMIT=80] Label for battery charging future pause -->
-    <string name="power_charging_future_paused"><xliff:g id="level">%1$s</xliff:g> - Charging optimized</string>
+    <string name="power_charging_future_paused"><xliff:g id="level">%1$s</xliff:g> - Charging</string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 249fa7f..e489bc5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1702,7 +1702,8 @@
         }
 
         public boolean isPrivateProfile() {
-            return UserManager.USER_TYPE_PROFILE_PRIVATE.equals(mProfileType);
+            return android.os.Flags.allowPrivateProfile()
+                    && UserManager.USER_TYPE_PROFILE_PRIVATE.equals(mProfileType);
         }
 
         /**
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
index 213a66e..1ad7d49 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
@@ -22,21 +22,30 @@
 import static org.mockito.Mockito.when;
 
 import android.content.pm.ApplicationInfo;
+import android.os.Flags;
 import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
 public class ApplicationsStateTest {
+    private static final int APP_ENTRY_ID = 1;
     private ApplicationsState.AppEntry mEntry;
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Before
     public void setUp() {
-        mEntry = mock(ApplicationsState.AppEntry.class);
-        mEntry.info = mock(ApplicationInfo.class);
+        mEntry = new ApplicationsState.AppEntry(
+                ApplicationProvider.getApplicationContext(),
+                mock(ApplicationInfo.class),
+                APP_ENTRY_ID);
     }
 
     @Test
@@ -310,6 +319,8 @@
 
     @Test
     public void testPrivateProfileFilterDisplaysCorrectApps() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
+
         mEntry.showInPersonalTab = true;
         mEntry.mProfileType = UserManager.USER_TYPE_FULL_SYSTEM;
         assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isTrue();
@@ -320,4 +331,14 @@
         assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isFalse();
         assertThat(ApplicationsState.FILTER_PRIVATE_PROFILE.filterApp(mEntry)).isTrue();
     }
+
+    @Test
+    public void testPrivateProfileFilterDisplaysCorrectAppsWhenFlagDisabled() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE);
+
+        mEntry.showInPersonalTab = false;
+        mEntry.mProfileType = UserManager.USER_TYPE_PROFILE_PRIVATE;
+        assertThat(ApplicationsState.FILTER_PERSONAL.filterApp(mEntry)).isFalse();
+        assertThat(ApplicationsState.FILTER_PRIVATE_PROFILE.filterApp(mEntry)).isFalse();
+    }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index cd35f67..be480b9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -308,11 +308,8 @@
                 final long token = proto.start(GenerationRegistryProto.BACKING_STORES);
                 final int key = mKeyToBackingStoreMap.keyAt(i);
                 proto.write(BackingStoreProto.KEY, key);
-                try {
-                    proto.write(BackingStoreProto.BACKING_STORE_SIZE,
-                            mKeyToBackingStoreMap.valueAt(i).size());
-                } catch (IOException ignore) {
-                }
+                proto.write(BackingStoreProto.BACKING_STORE_SIZE,
+                        mKeyToBackingStoreMap.valueAt(i).size());
                 proto.write(BackingStoreProto.NUM_CACHED_ENTRIES,
                         mKeyToIndexMapMap.get(key).size());
                 final ArrayMap<String, Integer> indexMap = mKeyToIndexMapMap.get(key);
@@ -357,10 +354,7 @@
                 pw.print("_Backing store for type:"); pw.print(SettingsState.settingTypeToString(
                         SettingsState.getTypeFromKey(key)));
                 pw.print(" user:"); pw.print(SettingsState.getUserIdFromKey(key));
-                try {
-                    pw.print(" size:" + mKeyToBackingStoreMap.valueAt(i).size());
-                } catch (IOException ignore) {
-                }
+                pw.print(" size:" + mKeyToBackingStoreMap.valueAt(i).size());
                 pw.println(" cachedEntries:" + mKeyToIndexMapMap.get(key).size());
                 final ArrayMap<String, Integer> indexMap = mKeyToIndexMapMap.get(key);
                 final MemoryIntArray backingStore = getBackingStoreLocked(key,
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp
index 6d63409..f74e59a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp
+++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
+}
+
 aconfig_declarations {
     name: "com_android_a11y_menu_flags",
     package: "com.android.systemui.accessibility.accessibilitymenu",
diff --git a/packages/SystemUI/aconfig/Android.bp b/packages/SystemUI/aconfig/Android.bp
index 5d0847c..76cb6bd 100644
--- a/packages/SystemUI/aconfig/Android.bp
+++ b/packages/SystemUI/aconfig/Android.bp
@@ -20,6 +20,7 @@
  */
 
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     default_visibility: [
         "//visibility:override",
         "//frameworks/base/packages/SystemUI:__subpackages__",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 2c285c8..4ed1965 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -29,6 +29,13 @@
 }
 
 flag {
+    name: "notification_color_update_logger"
+    namespace: "systemui"
+    description: "Enabled debug logging and dumping of notification color updates."
+    bug: "294347738"
+}
+
+flag {
     name: "notifications_footer_view_refactor"
     namespace: "systemui"
     description: "Enables the refactored version of the footer view in the notification shade "
@@ -67,6 +74,16 @@
 }
 
 flag {
+    name: "notifications_background_media_icons"
+    namespace: "systemui"
+    description: "Updates icons for media notifications in the background."
+    bug: "315143160"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "nssl_falsing_fix"
     namespace: "systemui"
     description: "Minor touch changes to prevent falsing errors in NSSL"
@@ -295,12 +312,12 @@
 }
 
 flag {
-   name: "centralized_status_bar_dimens_refactor"
+   name: "centralized_status_bar_height_fix"
    namespace: "systemui"
    description: "Refactors shade header and keyguard status bar to read status bar dimens from a"
         " central place, instead of reading resources directly. This is to take into account display"
         " cutouts and other special cases. "
-   bug: "317199366"
+   bug: "317016114"
    metadata {
         purpose: PURPOSE_BUGFIX
    }
@@ -434,6 +451,16 @@
 }
 
 flag {
+    name: "slice_manager_binder_call_background"
+    namespace: "systemui"
+    description: "Move the ISliceManager#getPinnedSpecs binder call to the background thread."
+    bug: "322745650"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
    name: "register_new_wallet_card_in_background"
    namespace: "systemui"
    description: "Decide whether the call to registerNewWalletCards method should be issued on background thread."
@@ -453,3 +480,12 @@
     }
 }
 
+flag {
+    name: "register_zen_mode_content_observer_background"
+    namespace: "systemui"
+    description: "Decide whether to register zen mode content observers in the background thread."
+    bug: "324515627"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index e4dc9be..5d5f12e 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -123,7 +123,7 @@
             val views = LinkedList<View>().apply { add(view) }
 
             while (views.isNotEmpty()) {
-                val v = views.removeFirst()
+                val v = views.removeAt(0)
                 if (v.background != null) {
                     return v.background
                 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
index 660fc5a..44fe883 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
@@ -127,7 +127,7 @@
                             }
                             with(notificationSection) {
                                 val splitShadeTopMargin: Dp =
-                                    if (Flags.centralizedStatusBarDimensRefactor()) {
+                                    if (Flags.centralizedStatusBarHeightFix()) {
                                         largeScreenHeaderHelper.getLargeScreenHeaderHeight().dp
                                     } else {
                                         dimensionResource(
diff --git a/packages/SystemUI/compose/scene/Android.bp b/packages/SystemUI/compose/scene/Android.bp
index 3424085..af1172b 100644
--- a/packages/SystemUI/compose/scene/Android.bp
+++ b/packages/SystemUI/compose/scene/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 828e34d..2e781e6 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -29,13 +29,17 @@
 import androidx.compose.ui.graphics.CompositingStrategy
 import androidx.compose.ui.graphics.drawscope.ContentDrawScope
 import androidx.compose.ui.graphics.drawscope.scale
-import androidx.compose.ui.layout.IntermediateMeasureScope
+import androidx.compose.ui.layout.ApproachLayoutModifierNode
+import androidx.compose.ui.layout.ApproachMeasureScope
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.LookaheadScope
 import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
 import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.layout.intermediateLayout
 import androidx.compose.ui.node.DrawModifierNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.round
@@ -91,23 +95,7 @@
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     key: ElementKey,
-): Modifier {
-    return this.then(ElementModifier(layoutImpl, scene, key))
-        // TODO(b/311132415): Move this into ElementNode once we can create a delegate
-        // IntermediateLayoutModifierNode.
-        .intermediateLayout { measurable, constraints ->
-            // TODO(b/311132415): No need to fetch the element and sceneState from the map anymore
-            // once this is merged into ElementNode.
-            val element = layoutImpl.elements.getValue(key)
-            val sceneState = element.sceneStates.getValue(scene.key)
-
-            val placeable = measure(layoutImpl, scene, element, sceneState, measurable, constraints)
-            layout(placeable.width, placeable.height) {
-                place(layoutImpl, scene, element, sceneState, placeable, placementScope = this)
-            }
-        }
-        .testTag(key.testTag)
-}
+): Modifier = this.then(ElementModifier(layoutImpl, scene, key)).testTag(key.testTag)
 
 /**
  * An element associated to [ElementNode]. Note that this element does not support updates as its
@@ -129,7 +117,7 @@
     private var layoutImpl: SceneTransitionLayoutImpl,
     private var scene: Scene,
     private var key: ElementKey,
-) : Modifier.Node(), DrawModifierNode {
+) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode {
     private var _element: Element? = null
     private val element: Element
         get() = _element!!
@@ -197,6 +185,31 @@
         maybePruneMaps(layoutImpl, prevElement, prevSceneState)
     }
 
+    override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
+        // TODO(b/324191441): Investigate whether making this check more complex (checking if this
+        // element is shared or transformed) would lead to better performance.
+        return layoutImpl.state.currentTransition == null
+    }
+
+    override fun Placeable.PlacementScope.isPlacementApproachComplete(
+        lookaheadCoordinates: LayoutCoordinates
+    ): Boolean {
+        // TODO(b/324191441): Investigate whether making this check more complex (checking if this
+        // element is shared or transformed) would lead to better performance.
+        return layoutImpl.state.currentTransition == null
+    }
+
+    @ExperimentalComposeUiApi
+    override fun ApproachMeasureScope.approachMeasure(
+        measurable: Measurable,
+        constraints: Constraints,
+    ): MeasureResult {
+        val placeable = measure(layoutImpl, scene, element, sceneState, measurable, constraints)
+        return layout(placeable.width, placeable.height) {
+            place(layoutImpl, scene, element, sceneState, placeable, placementScope = this)
+        }
+    }
+
     override fun ContentDrawScope.draw() {
         val drawScale = getDrawScale(layoutImpl, element, scene)
         if (drawScale == Scale.Default) {
@@ -368,7 +381,7 @@
 }
 
 @OptIn(ExperimentalComposeUiApi::class)
-private fun IntermediateMeasureScope.measure(
+private fun ApproachMeasureScope.measure(
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     element: Element,
@@ -431,7 +444,7 @@
 }
 
 @OptIn(ExperimentalComposeUiApi::class)
-private fun IntermediateMeasureScope.place(
+private fun ApproachMeasureScope.place(
     layoutImpl: SceneTransitionLayoutImpl,
     scene: Scene,
     element: Element,
@@ -439,6 +452,8 @@
     placeable: Placeable,
     placementScope: Placeable.PlacementScope,
 ) {
+    this as LookaheadScope
+
     with(placementScope) {
         // Update the offset (relative to the SceneTransitionLayout) this element has in this scene
         // when idle.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index c8fbad4..76e7c95 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -348,6 +348,8 @@
             // Compute the destination scene (and therefore offset) to settle in.
             val offset = swipeTransition.dragOffset
             val distance = swipeTransition.distance
+            var targetScene: Scene
+            var targetOffset: Float
             if (
                 shouldCommitSwipe(
                     offset,
@@ -356,12 +358,24 @@
                     wasCommitted = swipeTransition._currentScene == toScene,
                 )
             ) {
-                // Animate to the next scene
-                animateTo(targetScene = toScene, targetOffset = distance)
+                targetScene = toScene
+                targetOffset = distance
             } else {
-                // Animate to the initial scene
-                animateTo(targetScene = fromScene, targetOffset = 0f)
+                targetScene = fromScene
+                targetOffset = 0f
             }
+
+            if (
+                targetScene != swipeTransition._currentScene &&
+                    !layoutState.canChangeScene(targetScene.key)
+            ) {
+                // We wanted to change to a new scene but we are not allowed to, so we animate back
+                // to the current scene.
+                targetScene = swipeTransition._currentScene
+                targetOffset = if (targetScene == fromScene) 0f else distance
+            }
+
+            animateTo(targetScene = targetScene, targetOffset = targetOffset)
         } else {
             // We are doing an overscroll animation between scenes. In this case, we can also start
             // from the idle position.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 8c5a472..08399ff 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -232,7 +232,12 @@
                 scene(state.transitionState.currentScene).userActions[Back]?.let { result ->
                     // TODO(b/290184746): Handle predictive back and use result.distance if
                     // specified.
-                    BackHandler { with(state) { coroutineScope.onChangeScene(result.toScene) } }
+                    BackHandler {
+                        val targetScene = result.toScene
+                        if (state.canChangeScene(targetScene)) {
+                            with(state) { coroutineScope.onChangeScene(targetScene) }
+                        }
+                    }
                 }
 
                 Box {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index a8da551..662f33f 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -101,13 +101,30 @@
     ): TransitionState.Transition?
 }
 
-/** Return a [MutableSceneTransitionLayoutState] initially idle at [initialScene]. */
+/**
+ * Return a [MutableSceneTransitionLayoutState] initially idle at [initialScene].
+ *
+ * @param initialScene the initial scene to which this state is initialized.
+ * @param transitions the [SceneTransitions] used when this state is transitioning between scenes.
+ * @param canChangeScene whether we can transition to the given scene. This is called when the user
+ *   commits a transition to a new scene because of a [UserAction]. If [canChangeScene] returns
+ *   `true`, then the gesture will be committed and we will animate to the other scene. Otherwise,
+ *   the gesture will be cancelled and we will animate back to the current scene.
+ * @param stateLinks the [StateLink] connecting this [SceneTransitionLayoutState] to other
+ *   [SceneTransitionLayoutState]s.
+ */
 fun MutableSceneTransitionLayoutState(
     initialScene: SceneKey,
     transitions: SceneTransitions = SceneTransitions.Empty,
+    canChangeScene: (SceneKey) -> Boolean = { true },
     stateLinks: List<StateLink> = emptyList(),
 ): MutableSceneTransitionLayoutState {
-    return MutableSceneTransitionLayoutStateImpl(initialScene, transitions, stateLinks)
+    return MutableSceneTransitionLayoutStateImpl(
+        initialScene,
+        transitions,
+        canChangeScene,
+        stateLinks,
+    )
 }
 
 /**
@@ -120,18 +137,32 @@
  *   This is called when the user commits a transition to a new scene because of a [UserAction], for
  *   instance by triggering back navigation or by swiping to a new scene.
  * @param transitions the definition of the transitions used to animate a change of scene.
+ * @param canChangeScene whether we can transition to the given scene. This is called when the user
+ *   commits a transition to a new scene because of a [UserAction]. If [canChangeScene] returns
+ *   `true`, then [onChangeScene] will be called right afterwards with the same [SceneKey]. If it
+ *   returns `false`, the user action will be cancelled and we will animate back to the current
+ *   scene.
+ * @param stateLinks the [StateLink] connecting this [SceneTransitionLayoutState] to other
+ *   [SceneTransitionLayoutState]s.
  */
 @Composable
 fun updateSceneTransitionLayoutState(
     currentScene: SceneKey,
     onChangeScene: (SceneKey) -> Unit,
     transitions: SceneTransitions = SceneTransitions.Empty,
+    canChangeScene: (SceneKey) -> Boolean = { true },
     stateLinks: List<StateLink> = emptyList(),
 ): SceneTransitionLayoutState {
     return remember {
-            HoistedSceneTransitionLayoutScene(currentScene, transitions, onChangeScene, stateLinks)
+            HoistedSceneTransitionLayoutState(
+                currentScene,
+                transitions,
+                onChangeScene,
+                canChangeScene,
+                stateLinks,
+            )
         }
-        .apply { update(currentScene, onChangeScene, transitions, stateLinks) }
+        .apply { update(currentScene, onChangeScene, canChangeScene, transitions, stateLinks) }
 }
 
 @Stable
@@ -208,6 +239,9 @@
 
     private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
 
+    /** Whether we can transition to the given [scene]. */
+    internal abstract fun canChangeScene(scene: SceneKey): Boolean
+
     /**
      * Called when the [current scene][TransitionState.currentScene] should be changed to [scene].
      *
@@ -330,25 +364,30 @@
  * A [SceneTransitionLayout] whose current scene/source of truth is hoisted (its current value comes
  * from outside).
  */
-internal class HoistedSceneTransitionLayoutScene(
+internal class HoistedSceneTransitionLayoutState(
     initialScene: SceneKey,
     override var transitions: SceneTransitions,
     private var changeScene: (SceneKey) -> Unit,
+    private var canChangeScene: (SceneKey) -> Boolean,
     stateLinks: List<StateLink> = emptyList(),
 ) : BaseSceneTransitionLayoutState(initialScene, stateLinks) {
     private val targetSceneChannel = Channel<SceneKey>(Channel.CONFLATED)
 
-    override fun CoroutineScope.onChangeScene(scene: SceneKey) = changeScene(scene)
+    override fun canChangeScene(scene: SceneKey): Boolean = canChangeScene.invoke(scene)
+
+    override fun CoroutineScope.onChangeScene(scene: SceneKey) = changeScene.invoke(scene)
 
     @Composable
     fun update(
         currentScene: SceneKey,
         onChangeScene: (SceneKey) -> Unit,
+        canChangeScene: (SceneKey) -> Boolean,
         transitions: SceneTransitions,
         stateLinks: List<StateLink>,
     ) {
         SideEffect {
             this.changeScene = onChangeScene
+            this.canChangeScene = canChangeScene
             this.transitions = transitions
             this.stateLinks = stateLinks
 
@@ -361,7 +400,7 @@
                 // late.
                 val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey
                 animateToScene(
-                    layoutState = this@HoistedSceneTransitionLayoutScene,
+                    layoutState = this@HoistedSceneTransitionLayoutState,
                     target = newKey,
                     transitionKey = null,
                 )
@@ -374,6 +413,7 @@
 internal class MutableSceneTransitionLayoutStateImpl(
     initialScene: SceneKey,
     override var transitions: SceneTransitions,
+    private val canChangeScene: (SceneKey) -> Boolean = { true },
     stateLinks: List<StateLink> = emptyList(),
 ) : MutableSceneTransitionLayoutState, BaseSceneTransitionLayoutState(initialScene, stateLinks) {
     override fun setTargetScene(
@@ -388,6 +428,8 @@
         )
     }
 
+    override fun canChangeScene(scene: SceneKey): Boolean = canChangeScene.invoke(scene)
+
     override fun CoroutineScope.onChangeScene(scene: SceneKey) {
         setTargetScene(scene, coroutineScope = this)
     }
diff --git a/packages/SystemUI/compose/scene/tests/Android.bp b/packages/SystemUI/compose/scene/tests/Android.bp
index 13df35b..59cc63a 100644
--- a/packages/SystemUI/compose/scene/tests/Android.bp
+++ b/packages/SystemUI/compose/scene/tests/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index c91d298..fe53d5b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -51,8 +51,13 @@
     private class TestGestureScope(
         private val testScope: MonotonicClockTestScope,
     ) {
+        var canChangeScene: (SceneKey) -> Boolean = { true }
         private val layoutState =
-            MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)
+            MutableSceneTransitionLayoutStateImpl(
+                SceneA,
+                EmptyTestTransitions,
+                canChangeScene = { canChangeScene(it) },
+            )
 
         val mutableUserActionsA = mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC)
         val mutableUserActionsB = mutableMapOf(Swipe.Up to SceneC, Swipe.Down to SceneA)
@@ -890,4 +895,41 @@
         )
         assertThat(transitionState).isNotSameInstanceAs(firstTransition)
     }
+
+    @Test
+    fun blockTransition() = runGestureTest {
+        assertIdle(SceneA)
+
+        // Swipe up to scene B.
+        onDragStarted(overSlop = up(0.1f))
+        assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB)
+
+        // Block the transition when the user release their finger.
+        canChangeScene = { false }
+        onDragStopped(velocity = -velocityThreshold)
+        advanceUntilIdle()
+        assertIdle(SceneA)
+    }
+
+    @Test
+    fun blockInterceptedTransition() = runGestureTest {
+        assertIdle(SceneA)
+
+        // Swipe up to B.
+        onDragStarted(overSlop = up(0.1f))
+        assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB)
+        onDragStopped(velocity = -velocityThreshold)
+        assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
+
+        // Intercept the transition and swipe down back to scene A.
+        assertThat(sceneGestureHandler.shouldImmediatelyIntercept(startedPosition = null)).isTrue()
+        onDragStartedImmediately()
+
+        // Block the transition when the user release their finger.
+        canChangeScene = { false }
+        onDragStopped(velocity = velocityThreshold)
+
+        advanceUntilIdle()
+        assertIdle(SceneB)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/utils/Android.bp b/packages/SystemUI/compose/scene/tests/utils/Android.bp
index ff8fe75..9089e6a 100644
--- a/packages/SystemUI/compose/scene/tests/utils/Android.bp
+++ b/packages/SystemUI/compose/scene/tests/utils/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
diff --git a/packages/SystemUI/customization/tests/utils/Android.bp b/packages/SystemUI/customization/tests/utils/Android.bp
index 6db1410..e015455 100644
--- a/packages/SystemUI/customization/tests/utils/Android.bp
+++ b/packages/SystemUI/customization/tests/utils/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index 55cfcc2..ab55125 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -210,6 +210,32 @@
         }
 
     @Test
+    fun shouldHandleTouchesOnDetach() =
+        testScope.runTest {
+            val shouldHandleTouches by collectLastValue(mUdfpsOverlayInteractor.shouldHandleTouches)
+
+            // GIVEN view is attached + on the keyguard
+            mController.onViewAttached()
+            captureStatusBarStateListeners()
+            sendStatusBarStateChanged(StatusBarState.KEYGUARD)
+            whenever(mView.setPauseAuth(true)).thenReturn(true)
+            whenever(mView.unpausedAlpha).thenReturn(0)
+
+            // WHEN panelViewExpansion changes to expanded
+            val job = mController.listenForBouncerExpansion(this)
+            keyguardBouncerRepository.setPrimaryShow(true)
+            keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
+            runCurrent()
+
+            mController.onViewDetached()
+
+            // THEN UDFPS auth is paused and should not handle touches
+            assertThat(mController.shouldPauseAuth()).isTrue()
+            assertThat(shouldHandleTouches!!).isFalse()
+
+            job.cancel()
+        }
+    @Test
     fun fadeFromDialogSuggestedAlpha() =
         testScope.runTest {
             // GIVEN view is attached and status bar expansion is 1f
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 0ebcf56..63abc8f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -27,7 +27,6 @@
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.coroutines.collectValues
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dock.DockManagerFake
 import com.android.systemui.flags.FakeFeatureFlags
@@ -50,7 +49,6 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.FakeSharedPreferences
@@ -59,7 +57,6 @@
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -83,7 +80,6 @@
     @Mock private lateinit var activityStarter: ActivityStarter
     @Mock private lateinit var launchAnimator: DialogTransitionAnimator
     @Mock private lateinit var devicePolicyManager: DevicePolicyManager
-    @Mock private lateinit var shadeInteractor: ShadeInteractor
     @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
 
     private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -183,7 +179,6 @@
         underTest =
             KeyguardQuickAffordanceInteractor(
                 keyguardInteractor = withDeps.keyguardInteractor,
-                shadeInteractor = shadeInteractor,
                 lockPatternUtils = lockPatternUtils,
                 keyguardStateController = keyguardStateController,
                 userTracker = userTracker,
@@ -198,8 +193,6 @@
                 backgroundDispatcher = testDispatcher,
                 appContext = context,
             )
-
-        whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f))
     }
 
     @Test
@@ -346,25 +339,6 @@
         }
 
     @Test
-    fun quickAffordance_updateOncePerShadeExpansion() =
-        testScope.runTest {
-            val shadeExpansion = MutableStateFlow(0f)
-            whenever(shadeInteractor.anyExpansion).thenReturn(shadeExpansion)
-
-            val collectedValue by
-                collectValues(
-                    underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
-                )
-
-            val initialSize = collectedValue.size
-            for (i in 0..10) {
-                shadeExpansion.value = i / 10f
-            }
-
-            assertThat(collectedValue.size).isEqualTo(initialSize + 1)
-        }
-
-    @Test
     fun quickAffordanceAlwaysVisible_notVisible_restrictedByPolicyManager() =
         testScope.runTest {
             whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 3455050..3104842 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -18,8 +18,6 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import android.content.pm.UserInfo
-import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -27,21 +25,20 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
-import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
-import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
 import com.android.systemui.testKosmos
-import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -85,35 +82,21 @@
 
     @EnableFlags(FLAG_COMMUNAL_HUB)
     @Test
-    fun leftTransitionSceneKey_communalIsEnabled_communal() =
+    fun leftTransitionSceneKey_communalIsAvailable_communal() =
         testScope.runTest {
-            with(kosmos.fakeUserRepository) {
-                setUserInfos(listOf(PRIMARY_USER))
-                setSelectedUserInfo(PRIMARY_USER)
-            }
-            kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
-            val leftDestinationSceneKey by collectLastValue(underTest.leftDestinationSceneKey)
-            assertThat(leftDestinationSceneKey).isEqualTo(SceneKey.Communal)
-        }
-
-    @DisableFlags(FLAG_COMMUNAL_HUB)
-    @Test
-    fun leftTransitionSceneKey_communalIsDisabled_null() =
-        testScope.runTest {
-            with(kosmos.fakeUserRepository) {
-                setUserInfos(listOf(PRIMARY_USER))
-                setSelectedUserInfo(PRIMARY_USER)
-            }
-            kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false)
             val leftDestinationSceneKey by collectLastValue(underTest.leftDestinationSceneKey)
             assertThat(leftDestinationSceneKey).isNull()
+
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+            assertThat(leftDestinationSceneKey).isEqualTo(SceneKey.Communal)
         }
 
     private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
         return LockscreenSceneViewModel(
             applicationScope = testScope.backgroundScope,
             deviceEntryInteractor = kosmos.deviceEntryInteractor,
-            communalSettingsInteractor = kosmos.communalSettingsInteractor,
+            communalInteractor = kosmos.communalInteractor,
             longPress =
                 KeyguardLongPressViewModel(
                     interactor = mock(),
@@ -121,9 +104,4 @@
             notifications = kosmos.notificationsPlaceholderViewModel,
         )
     }
-
-    private companion object {
-        val PRIMARY_USER =
-            UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN)
-    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 7c30c7e..9f89d34 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -40,7 +40,7 @@
 import com.android.systemui.bouncer.ui.viewmodel.bouncerViewModel
 import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.classifier.falsingCollector
-import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
+import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -130,7 +130,7 @@
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
     private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
     private val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor }
-    private val communalSettingsInteractor by lazy { kosmos.communalSettingsInteractor }
+    private val communalInteractor by lazy { kosmos.communalInteractor }
 
     private val transitionState by lazy {
         MutableStateFlow<ObservableTransitionState>(
@@ -155,7 +155,7 @@
         LockscreenSceneViewModel(
             applicationScope = testScope.backgroundScope,
             deviceEntryInteractor = deviceEntryInteractor,
-            communalSettingsInteractor = communalSettingsInteractor,
+            communalInteractor = communalInteractor,
             longPress =
                 KeyguardLongPressViewModel(
                     interactor = mock(),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationContentDescriptionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationContentDescriptionTest.kt
index f67c70c..12473cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationContentDescriptionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationContentDescriptionTest.kt
@@ -62,36 +62,23 @@
         assertThat(description).isEqualTo(createDescriptionText(n, ""))
     }
 
-    @Test
-    fun nullNotification_descriptionIsAppName() {
-        val description = contentDescForNotification(context, null)
-        assertThat(description).isEqualTo(createDescriptionText(null, ""))
-    }
-
     private fun createNotification(
         title: String? = null,
         text: String? = null,
         ticker: String? = null
     ): Notification =
-        Notification.Builder(context)
+        Notification.Builder(context, "channel")
             .setContentTitle(title)
             .setContentText(text)
             .setTicker(ticker)
             .build()
 
     private fun getTestAppName(): String {
-        return getAppName(createNotification("", "", ""))
+        return createNotification("", "", "").loadHeaderAppName(mContext)
     }
 
-    private fun getAppName(n: Notification?) =
-        n?.let {
-            val builder = Notification.Builder.recoverBuilder(context, it)
-            builder.loadHeaderAppName()
-        }
-            ?: ""
-
     private fun createDescriptionText(n: Notification?, desc: String?): String {
-        val appName = getAppName(n)
+        val appName = n?.loadHeaderAppName(mContext)
         return context.getString(R.string.accessibility_desc_notification_icon, appName, desc)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 4c824c0..87d25dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -46,12 +46,12 @@
 import android.graphics.Region;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
@@ -75,8 +75,8 @@
 import org.mockito.junit.MockitoRule;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
+@RunWith(AndroidJUnit4.class)
 public class BaseHeadsUpManagerTest extends SysuiTestCase {
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
diff --git a/packages/SystemUI/shared/biometrics/Android.bp b/packages/SystemUI/shared/biometrics/Android.bp
index 2bd7d97..63de81d 100644
--- a/packages/SystemUI/shared/biometrics/Android.bp
+++ b/packages/SystemUI/shared/biometrics/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
index fdac37b..b0d6611 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
@@ -21,8 +21,12 @@
  *
  * If the user's fallback credential is owned by another profile user the [deviceCredentialOwnerId]
  * will differ from the user's [userId].
+ *
+ * If prompt requests to use the user's parent profile for device credential,
+ * [userIdForPasswordEntry] might differ from the user's [userId].
  */
 data class BiometricUserInfo(
     val userId: Int,
     val deviceCredentialOwnerId: Int = userId,
+    val userIdForPasswordEntry: Int = userId,
 )
diff --git a/packages/SystemUI/shared/keyguard/Android.bp b/packages/SystemUI/shared/keyguard/Android.bp
index 2181439..2b3c77a 100644
--- a/packages/SystemUI/shared/keyguard/Android.bp
+++ b/packages/SystemUI/shared/keyguard/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index a9928d8..63088aa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -20,6 +20,7 @@
 
 import android.app.PendingIntent;
 import android.net.Uri;
+import android.os.Handler;
 import android.os.Trace;
 import android.provider.Settings;
 import android.util.Log;
@@ -39,6 +40,9 @@
 
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
 import com.android.systemui.Dumpable;
+import com.android.systemui.Flags;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
 import com.android.systemui.plugins.ActivityStarter;
@@ -60,6 +64,8 @@
         Dumpable {
     private static final String TAG = "KeyguardSliceViewCtrl";
 
+    private final Handler mHandler;
+    private final Handler mBgHandler;
     private final ActivityStarter mActivityStarter;
     private final ConfigurationController mConfigurationController;
     private final TunerService mTunerService;
@@ -105,6 +111,8 @@
 
     @Inject
     public KeyguardSliceViewController(
+            @Main Handler handler,
+            @Background Handler bgHandler,
             KeyguardSliceView keyguardSliceView,
             ActivityStarter activityStarter,
             ConfigurationController configurationController,
@@ -112,6 +120,8 @@
             DumpManager dumpManager,
             DisplayTracker displayTracker) {
         super(keyguardSliceView);
+        mHandler = handler;
+        mBgHandler = bgHandler;
         mActivityStarter = activityStarter;
         mConfigurationController = configurationController;
         mTunerService = tunerService;
@@ -182,24 +192,34 @@
      * Update contents of the view.
      */
     public void refresh() {
-        Slice slice;
+
         Trace.beginSection("KeyguardSliceViewController#refresh");
-        // We can optimize performance and avoid binder calls when we know that we're bound
-        // to a Slice on the same process.
-        if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
-            KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
-            if (instance != null) {
-                slice = instance.onBindSlice(mKeyguardSliceUri);
+        try {
+            Slice slice;
+            if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
+                KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
+                if (instance != null) {
+                    if (Flags.sliceManagerBinderCallBackground()) {
+                        mBgHandler.post(() -> {
+                            Slice _slice = instance.onBindSlice(mKeyguardSliceUri);
+                            mHandler.post(() -> mObserver.onChanged(_slice));
+                        });
+                        return;
+                    }
+                    slice = instance.onBindSlice(mKeyguardSliceUri);
+                } else {
+                    Log.w(TAG, "Keyguard slice not bound yet?");
+                    slice = null;
+                }
             } else {
-                Log.w(TAG, "Keyguard slice not bound yet?");
-                slice = null;
+                // TODO: Make SliceViewManager injectable
+                slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(
+                        mKeyguardSliceUri);
             }
-        } else {
-            // TODO: Make SliceViewManager injectable
-            slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(mKeyguardSliceUri);
+            mObserver.onChanged(slice);
+        } finally {
+            Trace.endSection();
         }
-        mObserver.onChanged(slice);
-        Trace.endSection();
     }
 
     void showSlice(Slice slice) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index f5603ed..c3e7818 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -132,13 +132,13 @@
     override fun onViewAttached() {
         dialogManager.registerListener(dialogListener)
         dumpManager.registerDumpable(dumpTag, this)
-        udfpsOverlayInteractor.setHandleTouches(shouldHandle = true)
+        udfpsOverlayInteractor.setHandleTouches(shouldHandle = !shouldPauseAuth())
     }
 
     override fun onViewDetached() {
         dialogManager.unregisterListener(dialogListener)
         dumpManager.unregisterDumpable(dumpTag)
-        udfpsOverlayInteractor.setHandleTouches(shouldHandle = true)
+        udfpsOverlayInteractor.setHandleTouches(shouldHandle = !shouldPauseAuth())
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 018d92e..ec54e4ce 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -378,7 +378,7 @@
         }
     }
 
-    override fun onViewDetached() {
+    public override fun onViewDetached() {
         super.onViewDetached()
         alternateBouncerInteractor.setAlternateBouncerUIAvailable(false, uniqueIdentifier)
         faceDetectRunning = false
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractor.kt
index 191533c..23afb7c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractor.kt
@@ -7,9 +7,9 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.internal.widget.LockscreenCredential
 import com.android.internal.widget.VerifyCredentialResponse
-import com.android.systemui.res.R
 import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
 import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
 import kotlinx.coroutines.delay
@@ -29,6 +29,9 @@
     /** Get the effective user id (profile owner, if one exists) */
     fun getCredentialOwnerOrSelfId(userId: Int): Int
 
+    /** Get parent user profile (if exists) */
+    fun getParentProfileIdOrSelfId(userId: Int): Int
+
     /**
      * Verifies a credential and returns a stream of results.
      *
@@ -58,6 +61,9 @@
     override fun getCredentialOwnerOrSelfId(userId: Int): Int =
         userManager.getCredentialOwnerProfile(userId)
 
+    override fun getParentProfileIdOrSelfId(userId: Int): Int =
+        userManager.getProfileParent(userId).id
+
     override fun verifyCredential(
         request: BiometricPromptRequest.Credential,
         credential: LockscreenCredential,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
index 359e2e7..e3facff 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
@@ -75,20 +75,32 @@
                     PromptKind.Pin ->
                         BiometricPromptRequest.Credential.Pin(
                             info = promptInfo,
-                            userInfo = userInfo(userId),
+                            userInfo =
+                                userInfo(
+                                    userId,
+                                    promptInfo.shouldUseParentProfileForDeviceCredential()
+                                ),
                             operationInfo = operationInfo(challenge)
                         )
                     PromptKind.Pattern ->
                         BiometricPromptRequest.Credential.Pattern(
                             info = promptInfo,
-                            userInfo = userInfo(userId),
+                            userInfo =
+                                userInfo(
+                                    userId,
+                                    promptInfo.shouldUseParentProfileForDeviceCredential()
+                                ),
                             operationInfo = operationInfo(challenge),
                             stealthMode = credentialInteractor.isStealthModeActive(userId)
                         )
                     PromptKind.Password ->
                         BiometricPromptRequest.Credential.Password(
                             info = promptInfo,
-                            userInfo = userInfo(userId),
+                            userInfo =
+                                userInfo(
+                                    userId,
+                                    promptInfo.shouldUseParentProfileForDeviceCredential()
+                                ),
                             operationInfo = operationInfo(challenge)
                         )
                     else -> null
@@ -96,10 +108,17 @@
             }
             .distinctUntilChanged()
 
-    private fun userInfo(userId: Int): BiometricUserInfo =
+    private fun userInfo(
+        userId: Int,
+        useParentProfileForDeviceCredential: Boolean
+    ): BiometricUserInfo =
         BiometricUserInfo(
             userId = userId,
-            deviceCredentialOwnerId = credentialInteractor.getCredentialOwnerOrSelfId(userId)
+            deviceCredentialOwnerId = credentialInteractor.getCredentialOwnerOrSelfId(userId),
+            userIdForPasswordEntry =
+                if (useParentProfileForDeviceCredential)
+                    credentialInteractor.getParentProfileIdOrSelfId(userId)
+                else credentialInteractor.getCredentialOwnerOrSelfId(userId),
         )
 
     private fun operationInfo(challenge: Long): BiometricOperationInfo =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
index 0ad07ba..4ed786b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
@@ -12,12 +12,12 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.res.R
 import com.android.systemui.biometrics.ui.CredentialPasswordView
 import com.android.systemui.biometrics.ui.CredentialView
 import com.android.systemui.biometrics.ui.IPinPad
 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.firstOrNull
@@ -42,7 +42,7 @@
         view.repeatWhenAttached {
             // the header info never changes - do it early
             val header = viewModel.header.first()
-            passwordField.setTextOperationUser(UserHandle.of(header.user.deviceCredentialOwnerId))
+            passwordField.setTextOperationUser(UserHandle.of(header.user.userIdForPasswordEntry))
             viewModel.inputFlags.firstOrNull()?.let { flags -> passwordField.inputType = flags }
             if (requestFocusForInput) {
                 passwordField.requestFocus()
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
index 7150d69e..9876fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
@@ -222,13 +222,18 @@
             val buffers = dumpManager.getLogBuffers()
             val tableBuffers = dumpManager.getTableLogBuffers()
 
-            targets.forEach { target ->
-                findTargetInCollection(target, dumpables, buffers, tableBuffers)?.dump(pw, args)
-            }
+            val matches =
+                if (args.matchAll) {
+                    findAllMatchesInCollection(targets, dumpables, buffers, tableBuffers)
+                } else {
+                    findBestMatchesInCollection(targets, dumpables, buffers, tableBuffers)
+                }
+            matches.forEach { it.dump(pw, args) }
         } else {
             if (args.listOnly) {
                 val dumpables = dumpManager.getDumpables()
                 val buffers = dumpManager.getLogBuffers()
+                val tableBuffers = dumpManager.getTableLogBuffers()
 
                 pw.println("Dumpables:")
                 listTargetNames(dumpables, pw)
@@ -236,18 +241,23 @@
 
                 pw.println("Buffers:")
                 listTargetNames(buffers, pw)
+                pw.println()
+
+                pw.println("TableBuffers:")
+                listTargetNames(tableBuffers, pw)
             } else {
                 pw.println("Nothing to dump :(")
             }
         }
     }
 
+    /** Finds the best match for a particular target */
     private fun findTargetInCollection(
         target: String,
         dumpables: Collection<DumpableEntry>,
         logBuffers: Collection<LogBufferEntry>,
         tableBuffers: Collection<TableLogBufferEntry>,
-    ) =
+    ): DumpsysEntry? =
         sequence {
                 findBestTargetMatch(dumpables, target)?.let { yield(it) }
                 findBestTargetMatch(logBuffers, target)?.let { yield(it) }
@@ -256,6 +266,31 @@
             .sortedBy { it.name }
             .minByOrNull { it.name.length }
 
+    /** Finds the best match for each target, if any, in the order of the targets */
+    private fun findBestMatchesInCollection(
+        targets: List<String>,
+        dumpables: Collection<DumpableEntry>,
+        logBuffers: Collection<LogBufferEntry>,
+        tableBuffers: Collection<TableLogBufferEntry>,
+    ): List<DumpsysEntry> =
+        targets.mapNotNull { target ->
+            findTargetInCollection(target, dumpables, logBuffers, tableBuffers)
+        }
+
+    /** Finds all matches for any target, returning in the --list order. */
+    private fun findAllMatchesInCollection(
+        targets: List<String>,
+        dumpables: Collection<DumpableEntry>,
+        logBuffers: Collection<LogBufferEntry>,
+        tableBuffers: Collection<TableLogBufferEntry>,
+    ): List<DumpsysEntry> =
+        sequence {
+                yieldAll(dumpables.filter { it.matchesAny(targets) })
+                yieldAll(logBuffers.filter { it.matchesAny(targets) })
+                yieldAll(tableBuffers.filter { it.matchesAny(targets) })
+            }
+            .sortedBy { it.name }.toList()
+
     private fun dumpConfig(pw: PrintWriter) {
         config.dump(pw, arrayOf())
     }
@@ -272,6 +307,11 @@
         pw.println("etc.")
         pw.println()
 
+        pw.println("Print all matches, instead of the best match:")
+        pw.println("$ <invocation> --all <targets>")
+        pw.println("$ <invocation> --all Log")
+        pw.println()
+
         pw.println("Special commands:")
         pw.println("$ <invocation> dumpables")
         pw.println("$ <invocation> buffers")
@@ -325,9 +365,10 @@
                     "--help" -> {
                         pArgs.command = "help"
                     }
-                    // This flag is passed as part of the proto dump in Bug reports, we can ignore
-                    // it because this is our default behavior.
-                    "-a" -> {}
+                    "-a",
+                    "--all" -> {
+                        pArgs.matchAll = true
+                    }
                     else -> {
                         throw ArgParseException("Unknown flag: $arg")
                     }
@@ -386,15 +427,19 @@
         const val DUMPSYS_DUMPABLE_DIVIDER =
             "----------------------------------------------------------------------------"
 
+        private fun DumpsysEntry.matches(target: String) = name.endsWith(target)
+        private fun DumpsysEntry.matchesAny(targets: Collection<String>) =
+            targets.any { matches(it) }
+
         private fun findBestTargetMatch(c: Collection<DumpsysEntry>, target: String) =
-            c.asSequence().filter { it.name.endsWith(target) }.minByOrNull { it.name.length }
+            c.asSequence().filter { it.matches(target) }.minByOrNull { it.name.length }
 
         private fun findBestProtoTargetMatch(
             c: Collection<DumpableEntry>,
             target: String
         ): ProtoDumpable? =
             c.asSequence()
-                .filter { it.name.endsWith(target) }
+                .filter { it.matches(target) }
                 .filter { it.dumpable is ProtoDumpable }
                 .minByOrNull { it.name.length }
                 ?.dumpable as? ProtoDumpable
@@ -440,40 +485,34 @@
         }
 
         /**
-         * Utility to write a [DumpableEntry] to the given [PrintWriter] in a
-         * dumpsys-appropriate format.
+         * Utility to write a [DumpableEntry] to the given [PrintWriter] in a dumpsys-appropriate
+         * format.
          */
         private fun dumpDumpable(
-                entry: DumpableEntry,
-                pw: PrintWriter,
-                args: Array<String> = arrayOf(),
-        ) = pw.wrapSection(entry) {
-            entry.dumpable.dump(pw, args)
-        }
+            entry: DumpableEntry,
+            pw: PrintWriter,
+            args: Array<String> = arrayOf(),
+        ) = pw.wrapSection(entry) { entry.dumpable.dump(pw, args) }
 
         /**
-         * Utility to write a [LogBufferEntry] to the given [PrintWriter] in a
-         * dumpsys-appropriate format.
+         * Utility to write a [LogBufferEntry] to the given [PrintWriter] in a dumpsys-appropriate
+         * format.
          */
         private fun dumpBuffer(
-                entry: LogBufferEntry,
-                pw: PrintWriter,
-                tailLength: Int = 0,
-        ) = pw.wrapSection(entry) {
-            entry.buffer.dump(pw, tailLength)
-        }
+            entry: LogBufferEntry,
+            pw: PrintWriter,
+            tailLength: Int = 0,
+        ) = pw.wrapSection(entry) { entry.buffer.dump(pw, tailLength) }
 
         /**
          * Utility to write a [TableLogBufferEntry] to the given [PrintWriter] in a
          * dumpsys-appropriate format.
          */
         private fun dumpTableBuffer(
-                entry: TableLogBufferEntry,
-                pw: PrintWriter,
-                args: Array<String> = arrayOf(),
-        ) = pw.wrapSection(entry) {
-            entry.table.dump(pw, args)
-        }
+            entry: TableLogBufferEntry,
+            pw: PrintWriter,
+            args: Array<String> = arrayOf(),
+        ) = pw.wrapSection(entry) { entry.table.dump(pw, args) }
 
         /**
          * Zero-arg utility to write a [DumpsysEntry] to the given [PrintWriter] in a
@@ -513,6 +552,7 @@
     var tailLength: Int = 0
     var command: String? = null
     var listOnly = false
+    var matchAll = false
     var proto = false
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 8eb1a50..b0a3881 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -46,7 +46,6 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -56,7 +55,6 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
@@ -68,7 +66,6 @@
 @Inject
 constructor(
     private val keyguardInteractor: KeyguardInteractor,
-    private val shadeInteractor: ShadeInteractor,
     private val lockPatternUtils: LockPatternUtils,
     private val keyguardStateController: KeyguardStateController,
     private val userTracker: UserTracker,
@@ -103,10 +100,9 @@
             quickAffordanceAlwaysVisible(position),
             keyguardInteractor.isDozing,
             keyguardInteractor.isKeyguardShowing,
-            shadeInteractor.anyExpansion.map { it < 1.0f }.distinctUntilChanged(),
             biometricSettingsRepository.isCurrentUserInLockdown,
-        ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible, isUserInLockdown ->
-            if (!isDozing && isKeyguardShowing && isQuickSettingsVisible && !isUserInLockdown) {
+        ) { affordance, isDozing, isKeyguardShowing, isUserInLockdown ->
+            if (!isDozing && isKeyguardShowing && !isUserInLockdown) {
                 affordance
             } else {
                 KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
index 218af29..6a3b920 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -24,7 +24,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
-import com.android.systemui.Flags.centralizedStatusBarDimensRefactor
+import com.android.systemui.Flags.centralizedStatusBarHeightFix
 import com.android.systemui.Flags.migrateClocksToBlueprint
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.res.R
@@ -80,7 +80,7 @@
                 val useLargeScreenHeader =
                     context.resources.getBoolean(R.bool.config_use_large_screen_shade_header)
                 val marginTopLargeScreen =
-                    if (centralizedStatusBarDimensRefactor()) {
+                    if (centralizedStatusBarHeightFix()) {
                         largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight()
                     } else {
                         context.resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index fa18557..9afe8fc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -36,7 +36,7 @@
 constructor(
     @Application applicationScope: CoroutineScope,
     deviceEntryInteractor: DeviceEntryInteractor,
-    communalSettingsInteractor: CommunalSettingsInteractor,
+    communalInteractor: CommunalInteractor,
     val longPress: KeyguardLongPressViewModel,
     val notifications: NotificationsPlaceholderViewModel,
 ) {
@@ -56,7 +56,7 @@
 
     /** The key of the scene we should switch to when swiping left. */
     val leftDestinationSceneKey: StateFlow<SceneKey?> =
-        communalSettingsInteractor.isCommunalEnabled
+        communalInteractor.isCommunalAvailable
             .map { available -> if (available) SceneKey.Communal else null }
             .stateIn(
                 scope = applicationScope,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index c0d9644..4ee2db7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -18,7 +18,7 @@
 
 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
 
-import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor;
+import static com.android.systemui.Flags.centralizedStatusBarHeightFix;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -194,7 +194,7 @@
         int topPadding = QSUtils.getQsHeaderSystemIconsAreaHeight(mContext);
         if (!LargeScreenUtils.shouldUseLargeScreenShadeHeader(mContext.getResources())) {
             topPadding =
-                    centralizedStatusBarDimensRefactor()
+                    centralizedStatusBarHeightFix()
                             ? LargeScreenHeaderHelper.getLargeScreenHeaderHeight(mContext)
                             : mContext.getResources()
                                     .getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 1b504a8..24b2d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -52,7 +52,7 @@
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
+import com.android.systemui.qs.tiles.dialog.InternetDialogManager;
 import com.android.systemui.statusbar.connectivity.AccessPointController;
 import com.android.systemui.statusbar.connectivity.IconState;
 import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
@@ -83,7 +83,7 @@
     private int mLastTileState = LAST_STATE_UNKNOWN;
 
     protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback();
-    private final InternetDialogFactory mInternetDialogFactory;
+    private final InternetDialogManager mInternetDialogManager;
     final Handler mHandler;
 
     @Inject
@@ -99,11 +99,11 @@
             QSLogger qsLogger,
             NetworkController networkController,
             AccessPointController accessPointController,
-            InternetDialogFactory internetDialogFactory
+            InternetDialogManager internetDialogManager
     ) {
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
-        mInternetDialogFactory = internetDialogFactory;
+        mInternetDialogManager = internetDialogManager;
         mHandler = mainHandler;
         mController = networkController;
         mAccessPointController = accessPointController;
@@ -125,7 +125,7 @@
 
     @Override
     protected void handleClick(@Nullable View view) {
-        mHandler.post(() -> mInternetDialogFactory.create(true,
+        mHandler.post(() -> mInternetDialogManager.create(true,
                 mAccessPointController.canConfigMobileData(),
                 mAccessPointController.canConfigWifi(), view));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
index 13271c3..357743b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -33,7 +33,7 @@
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.qs.tiles.dialog.InternetDialogFactory
+import com.android.systemui.qs.tiles.dialog.InternetDialogManager
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.connectivity.AccessPointController
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.InternetTileBinder
@@ -44,18 +44,18 @@
 class InternetTileNewImpl
 @Inject
 constructor(
-    host: QSHost,
-    uiEventLogger: QsEventLogger,
-    @Background backgroundLooper: Looper,
-    @Main private val mainHandler: Handler,
-    falsingManager: FalsingManager,
-    metricsLogger: MetricsLogger,
-    statusBarStateController: StatusBarStateController,
-    activityStarter: ActivityStarter,
-    qsLogger: QSLogger,
-    viewModel: InternetTileViewModel,
-    private val internetDialogFactory: InternetDialogFactory,
-    private val accessPointController: AccessPointController,
+        host: QSHost,
+        uiEventLogger: QsEventLogger,
+        @Background backgroundLooper: Looper,
+        @Main private val mainHandler: Handler,
+        falsingManager: FalsingManager,
+        metricsLogger: MetricsLogger,
+        statusBarStateController: StatusBarStateController,
+        activityStarter: ActivityStarter,
+        qsLogger: QSLogger,
+        viewModel: InternetTileViewModel,
+        private val internetDialogManager: InternetDialogManager,
+        private val accessPointController: AccessPointController,
 ) :
     QSTileImpl<QSTile.BooleanState>(
         host,
@@ -86,7 +86,7 @@
 
     override fun handleClick(view: View?) {
         mainHandler.post {
-            internetDialogFactory.create(
+            internetDialogManager.create(
                 aboveStatusBar = true,
                 accessPointController.canConfigMobileData(),
                 accessPointController.canConfigWifi(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
rename to packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index 03e0c1e..0dd0a60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -61,7 +61,6 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
 import com.android.systemui.animation.DialogTransitionAnimator;
-import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.res.R;
@@ -72,23 +71,30 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
-import javax.inject.Inject;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
 
 /**
  * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
  */
-@SysUISingleton
-public class InternetDialog extends SystemUIDialog implements
-        InternetDialogController.InternetDialogCallback, Window.Callback {
+public class InternetDialogDelegate implements
+        SystemUIDialog.Delegate,
+        InternetDialogController.InternetDialogCallback {
     private static final String TAG = "InternetDialog";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    static final long PROGRESS_DELAY_MS = 1500L;
+    private static final String ABOVE_STATUS_BAR = "above_status_bar";
+    private static final String CAN_CONFIG_MOBILE_DATA = "can_config_mobile_data";
+    private static final String CAN_CONFIG_WIFI = "can_config_wifi";
+
     static final int MAX_NETWORK_COUNT = 4;
 
     private final Handler mHandler;
     private final Executor mBackgroundExecutor;
     private final DialogTransitionAnimator mDialogTransitionAnimator;
+    private final boolean mAboveStatusBar;
+    private final SystemUIDialog.Factory mSystemUIDialogFactory;
 
     @VisibleForTesting
     protected InternetAdapter mAdapter;
@@ -97,19 +103,16 @@
     @VisibleForTesting
     protected boolean mCanConfigWifi;
 
-    private InternetDialogFactory mInternetDialogFactory;
-    private SubscriptionManager mSubscriptionManager;
+    private final InternetDialogManager mInternetDialogManager;
     private TelephonyManager mTelephonyManager;
     @Nullable
     private AlertDialog mAlertDialog;
-    private UiEventLogger mUiEventLogger;
-    private Context mContext;
-    private InternetDialogController mInternetDialogController;
+    private final UiEventLogger mUiEventLogger;
+    private final InternetDialogController mInternetDialogController;
     private TextView mInternetDialogTitle;
     private TextView mInternetDialogSubTitle;
     private View mDivider;
     private ProgressBar mProgressBar;
-    private LinearLayout mInternetDialogLayout;
     private LinearLayout mConnectedWifListLayout;
     private LinearLayout mMobileNetworkLayout;
     private LinearLayout mSecondaryMobileNetworkLayout;
@@ -127,8 +130,6 @@
     private ImageView mSignalIcon;
     private TextView mMobileTitleText;
     private TextView mMobileSummaryText;
-    private TextView mSecondaryMobileTitleText;
-    private TextView mSecondaryMobileSummaryText;
     private TextView mAirplaneModeSummaryText;
     private Switch mMobileDataToggle;
     private View mMobileToggleDivider;
@@ -139,12 +140,12 @@
     protected Button mShareWifiButton;
     private Button mAirplaneModeButton;
     private Drawable mBackgroundOn;
-    private KeyguardStateController mKeyguard;
+    private final KeyguardStateController mKeyguard;
     @Nullable
     private Drawable mBackgroundOff = null;
-    private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    private boolean mCanConfigMobileData;
-    private boolean mCanChangeWifiState;
+    private int mDefaultDataSubId;
+    private final boolean mCanConfigMobileData;
+    private final boolean mCanChangeWifiState;
     // Wi-Fi entries
     private int mWifiNetworkHeight;
     @Nullable
@@ -157,26 +158,41 @@
 
     // Wi-Fi scanning progress bar
     protected boolean mIsProgressBarVisible;
+    private SystemUIDialog mDialog;
 
-    @Inject
-    public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
-            InternetDialogController internetDialogController, boolean canConfigMobileData,
-            boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
+    @AssistedFactory
+    public interface Factory {
+        InternetDialogDelegate create(
+                @Assisted(ABOVE_STATUS_BAR) boolean aboveStatusBar,
+                @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
+                @Assisted(CAN_CONFIG_WIFI) boolean canConfigWifi);
+    }
+
+    @AssistedInject
+    public InternetDialogDelegate(
+            Context context,
+            InternetDialogManager internetDialogManager,
+            InternetDialogController internetDialogController,
+            @Assisted(ABOVE_STATUS_BAR) boolean canConfigMobileData,
+            @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigWifi,
+            @Assisted(CAN_CONFIG_WIFI) boolean aboveStatusBar,
+            UiEventLogger uiEventLogger,
             DialogTransitionAnimator dialogTransitionAnimator,
-            @Main Handler handler, @Background Executor executor,
-            KeyguardStateController keyguardStateController) {
-        super(context);
+            @Main Handler handler,
+            @Background Executor executor,
+            KeyguardStateController keyguardStateController,
+            SystemUIDialog.Factory systemUIDialogFactory) {
+        mAboveStatusBar = aboveStatusBar;
+        mSystemUIDialogFactory = systemUIDialogFactory;
         if (DEBUG) {
             Log.d(TAG, "Init InternetDialog");
         }
 
         // Save the context that is wrapped with our theme.
-        mContext = getContext();
         mHandler = handler;
         mBackgroundExecutor = executor;
-        mInternetDialogFactory = internetDialogFactory;
+        mInternetDialogManager = internetDialogManager;
         mInternetDialogController = internetDialogController;
-        mSubscriptionManager = mInternetDialogController.getSubscriptionManager();
         mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
         mTelephonyManager = mInternetDialogController.getTelephonyManager();
         mCanConfigMobileData = canConfigMobileData;
@@ -187,31 +203,42 @@
         mUiEventLogger = uiEventLogger;
         mDialogTransitionAnimator = dialogTransitionAnimator;
         mAdapter = new InternetAdapter(mInternetDialogController);
-        if (!aboveStatusBar) {
-            getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
-        }
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public SystemUIDialog createDialog() {
+        SystemUIDialog dialog = mSystemUIDialogFactory.create(this);
+        if (!mAboveStatusBar) {
+            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+        }
+
+        if (mDialog != null) {
+            mDialog.dismiss();
+        }
+        mDialog = dialog;
+
+        return dialog;
+    }
+
+    @Override
+    public void onCreate(SystemUIDialog dialog, Bundle savedInstanceState) {
         if (DEBUG) {
             Log.d(TAG, "onCreate");
         }
+        Context context = dialog.getContext();
         mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW);
-        mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog,
-                null);
+        mDialogView = LayoutInflater.from(context).inflate(
+                R.layout.internet_connectivity_dialog, null);
         mDialogView.setAccessibilityPaneTitle(
-                mContext.getText(R.string.accessibility_desc_quick_settings));
-        final Window window = getWindow();
+                context.getText(R.string.accessibility_desc_quick_settings));
+        final Window window = dialog.getWindow();
         window.setContentView(mDialogView);
 
         window.setWindowAnimations(R.style.Animation_InternetDialog);
 
-        mWifiNetworkHeight = mContext.getResources()
+        mWifiNetworkHeight = context.getResources()
                 .getDimensionPixelSize(R.dimen.internet_dialog_wifi_network_height);
 
-        mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog);
         mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
         mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
         mDivider = mDialogView.requireViewById(R.id.divider);
@@ -239,20 +266,20 @@
         mMobileToggleDivider = mDialogView.requireViewById(R.id.mobile_toggle_divider);
         mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
         mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
-        mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
+        mBackgroundOn = context.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
         mInternetDialogTitle.setText(getDialogTitleText());
         mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
-        mBackgroundOff = mContext.getDrawable(R.drawable.internet_dialog_selected_effect);
-        setOnClickListener();
+        mBackgroundOff = context.getDrawable(R.drawable.internet_dialog_selected_effect);
+        setOnClickListener(dialog);
         mTurnWifiOnLayout.setBackground(null);
         mAirplaneModeButton.setVisibility(
                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
-        mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
+        mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(context));
         mWifiRecyclerView.setAdapter(mAdapter);
     }
 
     @Override
-    public void start() {
+    public void onStart(SystemUIDialog dialog) {
         if (DEBUG) {
             Log.d(TAG, "onStart");
         }
@@ -273,7 +300,7 @@
     }
 
     @Override
-    public void stop() {
+    public void onStop(SystemUIDialog dialog) {
         if (DEBUG) {
             Log.d(TAG, "onStop");
         }
@@ -288,7 +315,7 @@
         mShareWifiButton.setOnClickListener(null);
         mAirplaneModeButton.setOnClickListener(null);
         mInternetDialogController.onStop();
-        mInternetDialogFactory.destroyDialog();
+        mInternetDialogManager.destroyDialog();
     }
 
     @Override
@@ -296,8 +323,11 @@
         if (DEBUG) {
             Log.d(TAG, "dismissDialog");
         }
-        mInternetDialogFactory.destroyDialog();
-        dismiss();
+        mInternetDialogManager.destroyDialog();
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+        }
     }
 
     /**
@@ -334,11 +364,11 @@
         updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked);
     }
 
-    private void setOnClickListener() {
+    private void setOnClickListener(SystemUIDialog dialog) {
         mMobileNetworkLayout.setOnClickListener(v -> {
             int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
             if (autoSwitchNonDdsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-                showTurnOffAutoDataSwitchDialog(autoSwitchNonDdsSubId);
+                showTurnOffAutoDataSwitchDialog(dialog, autoSwitchNonDdsSubId);
             }
             mInternetDialogController.connectCarrierNetwork();
         });
@@ -346,10 +376,10 @@
             boolean isChecked = mMobileDataToggle.isChecked();
             if (!isChecked && shouldShowMobileDialog()) {
                 mMobileDataToggle.setChecked(true);
-                showTurnOffMobileDialog();
+                showTurnOffMobileDialog(dialog);
             } else if (mInternetDialogController.isMobileDataEnabled() != isChecked) {
-                mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId,
-                        isChecked, false);
+                mInternetDialogController.setMobileDataEnabled(
+                        dialog.getContext(), mDefaultDataSubId, isChecked, false);
             }
         });
         mConnectedWifListLayout.setOnClickListener(this::onClickConnectedWifi);
@@ -359,7 +389,7 @@
                     if (mInternetDialogController.isWifiEnabled() == isChecked) return;
                     mInternetDialogController.setWifiEnabled(isChecked);
                 });
-        mDoneButton.setOnClickListener(v -> dismiss());
+        mDoneButton.setOnClickListener(v -> dialog.dismiss());
         mShareWifiButton.setOnClickListener(v -> {
             if (mInternetDialogController.mayLaunchShareWifiSettings(mConnectedWifiEntry)) {
                 mUiEventLogger.log(InternetDialogEvent.SHARE_WIFI_QS_BUTTON_CLICKED);
@@ -378,6 +408,14 @@
 
     private void setMobileDataLayout(boolean activeNetworkIsCellular,
             boolean isCarrierNetworkActive) {
+
+        if (mDialog != null) {
+            setMobileDataLayout(mDialog, activeNetworkIsCellular, isCarrierNetworkActive);
+        }
+    }
+
+    private void setMobileDataLayout(SystemUIDialog dialog, boolean activeNetworkIsCellular,
+                                     boolean isCarrierNetworkActive) {
         boolean isNetworkConnected = activeNetworkIsCellular || isCarrierNetworkActive;
         // 1. Mobile network should be gone if airplane mode ON or the list of active
         //    subscriptionId is null.
@@ -431,19 +469,19 @@
                 if (stub != null) {
                     stub.inflate();
                 }
-                mSecondaryMobileNetworkLayout = findViewById(R.id.secondary_mobile_network_layout);
+                mSecondaryMobileNetworkLayout = dialog.findViewById(
+                        R.id.secondary_mobile_network_layout);
                 mSecondaryMobileNetworkLayout.setOnClickListener(
                         this::onClickConnectedSecondarySub);
                 mSecondaryMobileNetworkLayout.setBackground(mBackgroundOn);
 
-                mSecondaryMobileTitleText = mDialogView.requireViewById(
+                TextView mSecondaryMobileTitleText = mDialogView.requireViewById(
                         R.id.secondary_mobile_title);
                 mSecondaryMobileTitleText.setText(getMobileNetworkTitle(autoSwitchNonDdsSubId));
                 mSecondaryMobileTitleText.setTextAppearance(
                         R.style.TextAppearance_InternetDialog_Active);
 
-                mSecondaryMobileSummaryText =
-                        mDialogView.requireViewById(R.id.secondary_mobile_summary);
+                TextView mSecondaryMobileSummaryText = mDialogView.requireViewById(R.id.secondary_mobile_summary);
                 summary = getMobileNetworkSummary(autoSwitchNonDdsSubId);
                 if (!TextUtils.isEmpty(summary)) {
                     mSecondaryMobileSummaryText.setText(
@@ -465,7 +503,7 @@
                 ImageView mSecondaryMobileSettingsIcon =
                         mDialogView.requireViewById(R.id.secondary_settings_icon);
                 mSecondaryMobileSettingsIcon.setColorFilter(
-                        mContext.getColor(R.color.connected_network_primary_color));
+                        dialog.getContext().getColor(R.color.connected_network_primary_color));
 
                 // set secondary visual for default data sub
                 mMobileNetworkLayout.setBackground(mBackgroundOff);
@@ -473,7 +511,7 @@
                 mMobileSummaryText.setTextAppearance(
                         R.style.TextAppearance_InternetDialog_Secondary);
                 mSignalIcon.setColorFilter(
-                        mContext.getColor(R.color.connected_network_secondary_color));
+                        dialog.getContext().getColor(R.color.connected_network_secondary_color));
             } else {
                 mMobileNetworkLayout.setBackground(
                         isNetworkConnected ? mBackgroundOn : mBackgroundOff);
@@ -491,7 +529,8 @@
             // Set airplane mode to the summary for carrier network
             if (mInternetDialogController.isAirplaneModeEnabled()) {
                 mAirplaneModeSummaryText.setVisibility(View.VISIBLE);
-                mAirplaneModeSummaryText.setText(mContext.getText(R.string.airplane_mode));
+                mAirplaneModeSummaryText.setText(
+                        dialog.getContext().getText(R.string.airplane_mode));
                 mAirplaneModeSummaryText.setTextAppearance(secondaryRes);
             } else {
                 mAirplaneModeSummaryText.setVisibility(View.GONE);
@@ -523,7 +562,7 @@
 
     @MainThread
     private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
-        if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
+        if (mDialog == null || !isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
             mConnectedWifListLayout.setVisibility(View.GONE);
             mShareWifiButton.setVisibility(View.GONE);
             return;
@@ -534,7 +573,7 @@
         mConnectedWifiIcon.setImageDrawable(
                 mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
         mWifiSettingsIcon.setColorFilter(
-                mContext.getColor(R.color.connected_network_primary_color));
+                mDialog.getContext().getColor(R.color.connected_network_primary_color));
         if (mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
                 mConnectedWifiEntry) != null) {
             mShareWifiButton.setVisibility(View.VISIBLE);
@@ -593,7 +632,7 @@
     @MainThread
     private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled,
             boolean isDeviceLocked) {
-        if (isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) {
+        if (mDialog == null || isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) {
             mWifiScanNotifyLayout.setVisibility(View.GONE);
             return;
         }
@@ -602,7 +641,7 @@
                     AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
                     mInternetDialogController::launchWifiScanningSetting);
             mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify(
-                    getContext().getText(R.string.wifi_scan_notify_message), linkInfo));
+                    mDialog.getContext().getText(R.string.wifi_scan_notify_message), linkInfo));
             mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance());
         }
         mWifiScanNotifyLayout.setVisibility(View.VISIBLE);
@@ -657,7 +696,10 @@
     }
 
     private boolean shouldShowMobileDialog() {
-        boolean flag = Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA,
+        if (mDialog == null) {
+            return false;
+        }
+        boolean flag = Prefs.getBoolean(mDialog.getContext(), QS_HAS_TURNED_OFF_MOBILE_DATA,
                 false);
         if (mInternetDialogController.isMobileDataEnabled() && !flag) {
             return true;
@@ -665,40 +707,42 @@
         return false;
     }
 
-    private void showTurnOffMobileDialog() {
+    private void showTurnOffMobileDialog(SystemUIDialog dialog) {
+        Context context = dialog.getContext();
         CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
         boolean isInService = mInternetDialogController.isVoiceStateInService(mDefaultDataSubId);
         if (TextUtils.isEmpty(carrierName) || !isInService) {
-            carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
+            carrierName = context.getString(R.string.mobile_data_disable_message_default_carrier);
         }
-        mAlertDialog = new Builder(mContext)
+        mAlertDialog = new AlertDialog.Builder(context)
                 .setTitle(R.string.mobile_data_disable_title)
-                .setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
+                .setMessage(context.getString(R.string.mobile_data_disable_message, carrierName))
                 .setNegativeButton(android.R.string.cancel, (d, w) -> {
                 })
                 .setPositiveButton(
                         com.android.internal.R.string.alert_windows_notification_turn_off_action,
                         (d, w) -> {
-                            mInternetDialogController.setMobileDataEnabled(mContext,
+                            mInternetDialogController.setMobileDataEnabled(context,
                                     mDefaultDataSubId, false, false);
                             mMobileDataToggle.setChecked(false);
-                            Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
+                            Prefs.putBoolean(context, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
                         })
                 .create();
         mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
         SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
         SystemUIDialog.registerDismissListener(mAlertDialog);
         SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
-        mDialogTransitionAnimator.showFromDialog(mAlertDialog, this, null, false);
+        mDialogTransitionAnimator.showFromDialog(mAlertDialog, dialog, null, false);
     }
 
-    private void showTurnOffAutoDataSwitchDialog(int subId) {
+    private void showTurnOffAutoDataSwitchDialog(SystemUIDialog dialog, int subId) {
+        Context context = dialog.getContext();
         CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
         if (TextUtils.isEmpty(carrierName)) {
-            carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
+            carrierName = context.getString(R.string.mobile_data_disable_message_default_carrier);
         }
-        mAlertDialog = new Builder(mContext)
-                .setTitle(mContext.getString(R.string.auto_data_switch_disable_title, carrierName))
+        mAlertDialog = new AlertDialog.Builder(context)
+                .setTitle(context.getString(R.string.auto_data_switch_disable_title, carrierName))
                 .setMessage(R.string.auto_data_switch_disable_message)
                 .setNegativeButton(R.string.auto_data_switch_dialog_negative_button,
                         (d, w) -> {
@@ -716,7 +760,7 @@
         SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
         SystemUIDialog.registerDismissListener(mAlertDialog);
         SystemUIDialog.setWindowOnTop(mAlertDialog, mKeyguard.isShowing());
-        mDialogTransitionAnimator.showFromDialog(mAlertDialog, this, null, false);
+        mDialogTransitionAnimator.showFromDialog(mAlertDialog, dialog, null, false);
     }
 
     @Override
@@ -802,11 +846,10 @@
     }
 
     @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-        super.onWindowFocusChanged(hasFocus);
+    public void onWindowFocusChanged(SystemUIDialog dialog, boolean hasFocus) {
         if (mAlertDialog != null && !mAlertDialog.isShowing()) {
-            if (!hasFocus && isShowing()) {
-                dismiss();
+            if (!hasFocus && dialog.isShowing()) {
+                dialog.dismiss();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
similarity index 60%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
rename to packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
index c5f8983..2a177c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
@@ -15,64 +15,49 @@
  */
 package com.android.systemui.qs.tiles.dialog
 
-import android.content.Context
-import android.os.Handler
 import android.util.Log
 import android.view.View
 import com.android.internal.jank.InteractionJankMonitor
-import com.android.internal.logging.UiEventLogger
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import java.util.concurrent.Executor
+import com.android.systemui.statusbar.phone.SystemUIDialog
 import javax.inject.Inject
 
 private const val TAG = "InternetDialogFactory"
 private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
 
 /**
- * Factory to create [InternetDialog] objects.
+ * Factory to create [InternetDialogDelegate] objects.
  */
 @SysUISingleton
-class InternetDialogFactory @Inject constructor(
-    @Main private val handler: Handler,
-    @Background private val executor: Executor,
-    private val internetDialogController: InternetDialogController,
-    private val context: Context,
-    private val uiEventLogger: UiEventLogger,
+class InternetDialogManager @Inject constructor(
     private val dialogTransitionAnimator: DialogTransitionAnimator,
-    private val keyguardStateController: KeyguardStateController
+    private val dialogFactory: InternetDialogDelegate.Factory
 ) {
     companion object {
         private const val INTERACTION_JANK_TAG = "internet"
-        var internetDialog: InternetDialog? = null
+        var dialog: SystemUIDialog? = null
     }
 
-    /** Creates a [InternetDialog]. The dialog will be animated from [view] if it is not null. */
+    /** Creates a [InternetDialogDelegate]. The dialog will be animated from [view] if it is not null. */
     fun create(
         aboveStatusBar: Boolean,
         canConfigMobileData: Boolean,
         canConfigWifi: Boolean,
         view: View?
     ) {
-        if (internetDialog != null) {
+        if (dialog != null) {
             if (DEBUG) {
                 Log.d(TAG, "InternetDialog is showing, do not create it twice.")
             }
             return
         } else {
-            internetDialog = InternetDialog(
-                context, this, internetDialogController,
-                canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger,
-                    dialogTransitionAnimator, handler,
-                executor, keyguardStateController
-            )
+            dialog = dialogFactory.create(
+                    aboveStatusBar, canConfigMobileData, canConfigWifi).createDialog()
             if (view != null) {
                 dialogTransitionAnimator.showFromView(
-                    internetDialog!!, view,
+                        dialog!!, view,
                     animateBackgroundBoundsChange = true,
                     cuj = DialogCuj(
                         InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
@@ -80,7 +65,7 @@
                     )
                 )
             } else {
-                internetDialog?.show()
+                dialog!!.show()
             }
         }
     }
@@ -89,6 +74,6 @@
         if (DEBUG) {
             Log.d(TAG, "destroyDialog")
         }
-        internetDialog = null
+        dialog = null
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 457b3d7..29de688 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -27,7 +27,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import androidx.lifecycle.lifecycleScope
-import com.android.systemui.Flags.centralizedStatusBarDimensRefactor
+import com.android.systemui.Flags.centralizedStatusBarHeightFix
 import com.android.systemui.Flags.migrateClocksToBlueprint
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
@@ -183,7 +183,7 @@
     }
 
     private fun calculateLargeShadeHeaderHeight(): Int {
-        return if (centralizedStatusBarDimensRefactor()) {
+        return if (centralizedStatusBarHeightFix()) {
             largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight()
         } else {
             resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index f86c71b..f7b9e4e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -20,7 +20,7 @@
 import static android.view.WindowInsets.Type.ime;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
-import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor;
+import static com.android.systemui.Flags.centralizedStatusBarHeightFix;
 import static com.android.systemui.Flags.migrateClocksToBlueprint;
 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
 import static com.android.systemui.shade.NotificationPanelViewController.COUNTER_PANEL_OPEN_QS;
@@ -453,7 +453,7 @@
         mUseLargeScreenShadeHeader =
                 LargeScreenUtils.shouldUseLargeScreenShadeHeader(mPanelView.getResources());
         mLargeScreenShadeHeaderHeight =
-                centralizedStatusBarDimensRefactor()
+                centralizedStatusBarHeightFix()
                         ? mLargeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight()
                         : mResources.getDimensionPixelSize(
                                 R.dimen.large_screen_shade_header_height);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index a66bacd..df9c57c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -38,7 +38,7 @@
 import com.android.app.animation.Interpolators
 import com.android.settingslib.Utils
 import com.android.systemui.Dumpable
-import com.android.systemui.Flags.centralizedStatusBarDimensRefactor
+import com.android.systemui.Flags.centralizedStatusBarHeightFix
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
@@ -433,7 +433,7 @@
             changes += combinedShadeHeadersConstraintManager.emptyCutoutConstraints()
         }
 
-        if (centralizedStatusBarDimensRefactor()) {
+        if (centralizedStatusBarHeightFix()) {
             view.setPadding(view.paddingLeft, sbInsets.top, view.paddingRight, view.paddingBottom)
         }
         view.updateAllConstraints(changes)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index ffb11dd..ca19f71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -177,6 +177,7 @@
     private static final int MSG_CONFIRM_IMMERSIVE_PROMPT = 77 << MSG_SHIFT;
     private static final int MSG_IMMERSIVE_CHANGED = 78 << MSG_SHIFT;
     private static final int MSG_SET_QS_TILES = 79 << MSG_SHIFT;
+    private static final int MSG_ENTER_DESKTOP = 80 << MSG_SHIFT;
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
     public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
@@ -520,6 +521,11 @@
          * @see IStatusBar#immersiveModeChanged
          */
         default void immersiveModeChanged(int rootDisplayAreaId, boolean isImmersiveMode) {}
+
+        /**
+         * @see IStatusBar#enterDesktop(int)
+         */
+        default void enterDesktop(int displayId) {}
     }
 
     @VisibleForTesting
@@ -1420,6 +1426,13 @@
         mHandler.obtainMessage(MSG_GO_TO_FULLSCREEN_FROM_SPLIT).sendToTarget();
     }
 
+    @Override
+    public void enterDesktop(int displayId) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = displayId;
+        mHandler.obtainMessage(MSG_ENTER_DESKTOP, args).sendToTarget();
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -1914,6 +1927,13 @@
                         mCallbacks.get(i).immersiveModeChanged(rootDisplayAreaId, isImmersiveMode);
                     }
                     break;
+                case MSG_ENTER_DESKTOP:
+                    args = (SomeArgs) msg.obj;
+                    int displayId = args.argi1;
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).enterDesktop(displayId);
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 0e0f152..6155348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -42,6 +43,7 @@
 import com.android.systemui.flags.RefactorFlag;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -187,8 +189,8 @@
 
     @Override
     public String toString() {
-        return "NotificationShelf"
-                + "(hideBackground=" + mHideBackground
+        return super.toString()
+                + " (hideBackground=" + mHideBackground
                 + " notGoneIndex=" + mNotGoneIndex
                 + " hasItemsInStableShelf=" + mHasItemsInStableShelf
                 + " interactive=" + mInteractive
@@ -368,6 +370,17 @@
                 && isYInView(localY, slop, top, bottom);
     }
 
+    @Override
+    public void updateBackgroundColors() {
+        super.updateBackgroundColors();
+        ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+        if (colorUpdateLogger != null) {
+            colorUpdateLogger.logEvent("Shelf.updateBackgroundColors()",
+                    "normalBgColor=" + hexColorString(getNormalBgColor())
+                            + " background=" + mBackgroundNormal.toDumpString());
+        }
+    }
+
     /**
      * Update the shelf appearance based on the other notifications around it. This transforms
      * the icons from the notification area into the shelf.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index fc84973..724b19c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -61,7 +61,6 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -72,7 +71,8 @@
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.LogLevel;
 import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
-import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
+import com.android.systemui.qs.tiles.dialog.InternetDialogManager;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -83,8 +83,6 @@
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.util.CarrierConfigTracker;
 
-import dalvik.annotation.optimization.NeverCompile;
-
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -99,6 +97,7 @@
 
 import javax.inject.Inject;
 
+import dalvik.annotation.optimization.NeverCompile;
 import kotlin.Unit;
 
 /** Platform implementation of the network controller. **/
@@ -201,7 +200,7 @@
     private boolean mUserSetup;
     private boolean mSimDetected;
     private boolean mForceCellularValidated;
-    private InternetDialogFactory mInternetDialogFactory;
+    private InternetDialogManager mInternetDialogManager;
     private Handler mMainHandler;
 
     private ConfigurationController.ConfigurationListener mConfigurationListener =
@@ -245,7 +244,7 @@
             WifiStatusTrackerFactory trackerFactory,
             MobileSignalControllerFactory mobileFactory,
             @Main Handler handler,
-            InternetDialogFactory internetDialogFactory,
+            InternetDialogManager internetDialogManager,
             DumpManager dumpManager,
             @StatusBarNetworkControllerLog LogBuffer logBuffer) {
         this(context, connectivityManager,
@@ -272,7 +271,7 @@
                 dumpManager,
                 logBuffer);
         mReceiverHandler.post(mRegisterListeners);
-        mInternetDialogFactory = internetDialogFactory;
+        mInternetDialogManager = internetDialogManager;
     }
 
     @VisibleForTesting
@@ -829,7 +828,7 @@
                 mReceiverHandler.post(this::handleConfigurationChanged);
                 break;
             case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
-                mMainHandler.post(() -> mInternetDialogFactory.create(true,
+                mMainHandler.post(() -> mInternetDialogManager.create(true,
                         mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(),
                         null /* view */));
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
index 6429815..11636bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
@@ -17,6 +17,8 @@
 package com.android.systemui.statusbar.data.repository
 
 import android.graphics.Rect
+import android.view.InsetsFlags
+import android.view.ViewDebug
 import android.view.WindowInsets
 import android.view.WindowInsetsController
 import android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS
@@ -305,8 +307,8 @@
         letterboxDetails.isNotEmpty()
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
-        pw.println("originalStatusBarAttributes: ${_originalStatusBarAttributes.value}")
-        pw.println("modifiedStatusBarAttributes: ${modifiedStatusBarAttributes.value}")
+        pw.println("${_originalStatusBarAttributes.value}")
+        pw.println("${modifiedStatusBarAttributes.value}")
         pw.println("statusBarMode: ${statusBarMode.value}")
     }
 
@@ -320,7 +322,20 @@
         val navbarColorManagedByIme: Boolean,
         @WindowInsets.Type.InsetsType val requestedVisibleTypes: Int,
         val letterboxDetails: List<LetterboxDetails>,
-    )
+    ) {
+        override fun toString(): String {
+            return """
+                StatusBarAttributes(
+                    appearance=${appearance.toAppearanceString()},
+                    appearanceRegions=$appearanceRegions,
+                    navbarColorManagedByIme=$navbarColorManagedByIme,
+                    requestedVisibleTypes=${requestedVisibleTypes.toWindowInsetsString()},
+                    letterboxDetails=$letterboxDetails
+                    )
+                    """
+                .trimIndent()
+        }
+    }
 
     /**
      * Internal class keeping track of how [StatusBarAttributes] were transformed into new
@@ -331,9 +346,31 @@
         val appearanceRegions: List<AppearanceRegion>,
         val navbarColorManagedByIme: Boolean,
         val statusBarBounds: BoundsPair,
-    )
+    ) {
+        override fun toString(): String {
+            return """
+                ModifiedStatusBarAttributes(
+                    appearance=${appearance.toAppearanceString()},
+                    appearanceRegions=$appearanceRegions,
+                    navbarColorManagedByIme=$navbarColorManagedByIme,
+                    statusBarBounds=$statusBarBounds
+                    )
+                    """
+                .trimIndent()
+        }
+    }
 }
 
+private fun @receiver:WindowInsets.Type.InsetsType Int.toWindowInsetsString() =
+    "[${WindowInsets.Type.toString(this).replace(" ", ", ")}]"
+
+private fun @receiver:Appearance Int.toAppearanceString() =
+    if (this == 0) {
+        "NONE"
+    } else {
+        ViewDebug.flagsToString(InsetsFlags::class.java, "appearance", this)
+    }
+
 @AssistedFactory
 interface StatusBarModePerDisplayRepositoryFactory {
     fun create(@Assisted("displayId") displayId: Int): StatusBarModePerDisplayRepositoryImpl
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
new file mode 100644
index 0000000..c416d43
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+import android.icu.text.SimpleDateFormat
+import android.util.IndentingPrintWriter
+import com.android.systemui.Dumpable
+import com.android.systemui.Flags.notificationColorUpdateLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.util.Compile
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.printCollection
+import com.android.systemui.util.withIncreasedIndent
+import com.google.errorprone.annotations.CompileTimeConstant
+import java.io.PrintWriter
+import java.util.Locale
+import java.util.SortedSet
+import java.util.TreeSet
+import javax.inject.Inject
+
+@SysUISingleton
+class ColorUpdateLogger
+@Inject
+constructor(
+    val featureFlags: FeatureFlagsClassic,
+    dumpManager: DumpManager,
+) : Dumpable {
+
+    inline val isEnabled
+        get() = Compile.IS_DEBUG && notificationColorUpdateLogger()
+    private val frames: MutableList<Frame> = mutableListOf()
+
+    init {
+        dumpManager.registerDumpable(this)
+        if (isEnabled) {
+            instance = this
+        }
+    }
+
+    @JvmOverloads
+    fun logTriggerEvent(@CompileTimeConstant type: String, extra: String? = null) {
+        if (!isEnabled) return
+        val event = Event(type = type, extraValue = extra)
+        val didAppend = frames.lastOrNull()?.tryAddTrigger(event) == true
+        if (!didAppend) {
+            frames.add(Frame(event))
+            if (frames.size > maxFrames) frames.removeAt(0)
+        }
+    }
+
+    @JvmOverloads
+    fun logEvent(@CompileTimeConstant type: String, extra: String? = null) {
+        if (!isEnabled) return
+        val frame = frames.lastOrNull() ?: return
+        frame.events.add(Event(type = type, extraValue = extra))
+        frame.trim()
+    }
+
+    @JvmOverloads
+    fun logNotificationEvent(
+        @CompileTimeConstant type: String,
+        key: String,
+        extra: String? = null
+    ) {
+        if (!isEnabled) return
+        val frame = frames.lastOrNull() ?: return
+        frame.events.add(Event(type = type, extraValue = extra, notificationKey = key))
+        frame.trim()
+    }
+
+    override fun dump(pwOrig: PrintWriter, args: Array<out String>) {
+        val pw = pwOrig.asIndenting()
+        pw.println("enabled: $isEnabled")
+        pw.printCollection("frames", frames) { it.dump(pw) }
+    }
+
+    private class Frame(event: Event) {
+        val startTime: Long = event.time
+        val events: MutableList<Event> = mutableListOf(event)
+        val triggers: SortedSet<String> = TreeSet<String>().apply { add(event.type) }
+        var trimmedEvents: Int = 0
+
+        fun tryAddTrigger(newEvent: Event): Boolean {
+            if (newEvent.time < startTime) return false
+            if (newEvent.time - startTime > triggerStartsNewFrameAge) return false
+            if (newEvent.type in triggers) return false
+            triggers.add(newEvent.type)
+            events.add(newEvent)
+            trim()
+            return true
+        }
+
+        fun trim() {
+            if (events.size > maxEventsPerFrame) {
+                events.removeFirst()
+                trimmedEvents++
+            }
+        }
+
+        fun dump(pw: IndentingPrintWriter) {
+            pw.println("Frame")
+            pw.withIncreasedIndent {
+                pw.println("startTime: ${timeString(startTime)}")
+                pw.printCollection("triggers", triggers)
+                pw.println("trimmedEvents: $trimmedEvents")
+                pw.printCollection("events", events) { it.dump(pw) }
+            }
+        }
+    }
+
+    private class Event(
+        @CompileTimeConstant val type: String,
+        val extraValue: String? = null,
+        val notificationKey: String? = null,
+    ) {
+        val time: Long = System.currentTimeMillis()
+
+        fun dump(pw: IndentingPrintWriter) {
+            pw.append(timeString(time)).append(": ").append(type)
+            extraValue?.let { pw.append(" ").append(it) }
+            notificationKey?.let { pw.append(" ---- ").append(logKey(it)) }
+            pw.println()
+        }
+    }
+
+    private companion object {
+        @JvmStatic
+        var instance: ColorUpdateLogger? = null
+            private set
+        private const val maxFrames = 5
+        private const val maxEventsPerFrame = 250
+        private const val triggerStartsNewFrameAge = 5000
+
+        private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
+        private fun timeString(time: Long): String = dateFormat.format(time)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationContentDescription.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationContentDescription.kt
index 17fc5c6..bdd9fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationContentDescription.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationContentDescription.kt
@@ -26,11 +26,11 @@
 
 /** Returns accessibility content description for a given notification. */
 @MainThread
-fun contentDescForNotification(c: Context, n: Notification?): CharSequence {
-    val appName = n?.loadHeaderAppName(c) ?: ""
-    val title = n?.extras?.getCharSequence(Notification.EXTRA_TITLE)
-    val text = n?.extras?.getCharSequence(Notification.EXTRA_TEXT)
-    val ticker = n?.tickerText
+fun contentDescForNotification(c: Context, n: Notification): CharSequence {
+    val appName = n.loadHeaderAppName(c) ?: ""
+    val title = n.extras?.getCharSequence(Notification.EXTRA_TITLE)
+    val text = n.extras?.getCharSequence(Notification.EXTRA_TEXT)
+    val ticker = n.tickerText
 
     // Some apps just put the app name into the title
     val titleOrText = if (TextUtils.equals(title, appName)) text else title
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
index 0be4bde..16af9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -22,7 +22,10 @@
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Flags;
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -53,32 +56,13 @@
 
     private final NotifFilter mMediaFilter = new NotifFilter(TAG) {
         @Override
-        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+        public boolean shouldFilterOut(@NonNull NotificationEntry entry, long now) {
             if (!mIsMediaFeatureEnabled || !isMediaNotification(entry.getSbn())) {
                 return false;
             }
 
-            switch (mIconsState.getOrDefault(entry, STATE_ICONS_UNINFLATED)) {
-                case STATE_ICONS_UNINFLATED:
-                    try {
-                        mIconManager.createIcons(entry);
-                        mIconsState.put(entry, STATE_ICONS_INFLATED);
-                    } catch (InflationException e) {
-                        reportInflationError(entry, e);
-                        mIconsState.put(entry, STATE_ICONS_ERROR);
-                    }
-                    break;
-                case STATE_ICONS_INFLATED:
-                    try {
-                        mIconManager.updateIcons(entry);
-                    } catch (InflationException e) {
-                        reportInflationError(entry, e);
-                        mIconsState.put(entry, STATE_ICONS_ERROR);
-                    }
-                    break;
-                case STATE_ICONS_ERROR:
-                    // do nothing
-                    break;
+            if (!Flags.notificationsBackgroundMediaIcons()) {
+                inflateOrUpdateIcons(entry);
             }
 
             return true;
@@ -87,24 +71,67 @@
 
     private final NotifCollectionListener mCollectionListener = new NotifCollectionListener() {
         @Override
-        public void onEntryInit(NotificationEntry entry) {
-            mIconsState.put(entry, STATE_ICONS_UNINFLATED);
-        }
-
-        @Override
-        public void onEntryUpdated(NotificationEntry entry) {
-            if (mIconsState.getOrDefault(entry, STATE_ICONS_UNINFLATED) == STATE_ICONS_ERROR) {
-                // The update may have fixed the inflation error, so give it another chance.
+        public void onEntryInit(@NonNull NotificationEntry entry) {
+            // We default to STATE_ICONS_UNINFLATED anyway, so there's no need to initialize it.
+            if (!Flags.notificationsBackgroundMediaIcons()) {
                 mIconsState.put(entry, STATE_ICONS_UNINFLATED);
             }
         }
 
         @Override
-        public void onEntryCleanUp(NotificationEntry entry) {
+        public void onEntryAdded(@NonNull NotificationEntry entry) {
+            if (Flags.notificationsBackgroundMediaIcons()) {
+                if (isMediaNotification(entry.getSbn())) {
+                    inflateOrUpdateIcons(entry);
+                }
+            }
+        }
+
+        @Override
+        public void onEntryUpdated(@NonNull NotificationEntry entry) {
+            if (mIconsState.getOrDefault(entry, STATE_ICONS_UNINFLATED) == STATE_ICONS_ERROR) {
+                // The update may have fixed the inflation error, so give it another chance.
+                mIconsState.put(entry, STATE_ICONS_UNINFLATED);
+            }
+
+            if (Flags.notificationsBackgroundMediaIcons()) {
+                if (isMediaNotification(entry.getSbn())) {
+                    inflateOrUpdateIcons(entry);
+                }
+            }
+        }
+
+        @Override
+        public void onEntryCleanUp(@NonNull NotificationEntry entry) {
             mIconsState.remove(entry);
         }
     };
 
+    private void inflateOrUpdateIcons(NotificationEntry entry) {
+        switch (mIconsState.getOrDefault(entry, STATE_ICONS_UNINFLATED)) {
+            case STATE_ICONS_UNINFLATED:
+                try {
+                    mIconManager.createIcons(entry);
+                    mIconsState.put(entry, STATE_ICONS_INFLATED);
+                } catch (InflationException e) {
+                    reportInflationError(entry, e);
+                    mIconsState.put(entry, STATE_ICONS_ERROR);
+                }
+                break;
+            case STATE_ICONS_INFLATED:
+                try {
+                    mIconManager.updateIcons(entry);
+                } catch (InflationException e) {
+                    reportInflationError(entry, e);
+                    mIconsState.put(entry, STATE_ICONS_ERROR);
+                }
+                break;
+            case STATE_ICONS_ERROR:
+                // do nothing
+                break;
+        }
+    }
+
     private void reportInflationError(NotificationEntry entry, Exception e) {
         // This is the same logic as in PreparationCoordinator; it doesn't handle media
         // notifications when the media feature is enabled since they aren't displayed in the shade,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index 3809ea0..b8a9594 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -23,6 +23,7 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
+import com.android.systemui.statusbar.notification.ColorUpdateLogger
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
@@ -41,7 +42,8 @@
     private val mConfigurationController: ConfigurationController,
     private val mLockscreenUserManager: NotificationLockscreenUserManager,
     private val mGutsManager: NotificationGutsManager,
-    private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor
+    private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val colorUpdateLogger: ColorUpdateLogger,
 ) : Coordinator, ConfigurationController.ConfigurationListener {
 
     private var mIsSwitchingUser = false
@@ -51,11 +53,13 @@
 
     private val mKeyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
         override fun onUserSwitching(userId: Int) {
+            colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitching()")
             log { "ViewConfigCoordinator.onUserSwitching(userId=$userId)" }
             mIsSwitchingUser = true
         }
 
         override fun onUserSwitchComplete(userId: Int) {
+            colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitchComplete()")
             log { "ViewConfigCoordinator.onUserSwitchComplete(userId=$userId)" }
             mIsSwitchingUser = false
             applyChangesOnUserSwitched()
@@ -64,6 +68,7 @@
 
     private val mUserChangedListener = object : UserChangedListener {
         override fun onUserChanged(userId: Int) {
+            colorUpdateLogger.logTriggerEvent("VCC.mUserChangedListener.onUserChanged()")
             log { "ViewConfigCoordinator.onUserChanged(userId=$userId)" }
             applyChangesOnUserSwitched()
         }
@@ -77,6 +82,7 @@
     }
 
     override fun onDensityOrFontScaleChanged() {
+        colorUpdateLogger.logTriggerEvent("VCC.onDensityOrFontScaleChanged()")
         log {
             val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
             "ViewConfigCoordinator.onDensityOrFontScaleChanged()" +
@@ -93,6 +99,7 @@
     }
 
     override fun onUiModeChanged() {
+        colorUpdateLogger.logTriggerEvent("VCC.onUiModeChanged()")
         log {
             val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
             "ViewConfigCoordinator.onUiModeChanged()" +
@@ -107,10 +114,12 @@
     }
 
     override fun onThemeChanged() {
+        colorUpdateLogger.logTriggerEvent("VCC.onThemeChanged()")
         onDensityOrFontScaleChanged()
     }
 
     private fun applyChangesOnUserSwitched() {
+        colorUpdateLogger.logEvent("VCC.applyChangesOnUserSwitched()")
         if (mReinflateNotificationsOnUserSwitched) {
             updateNotificationsOnDensityOrFontScaleChanged()
             mReinflateNotificationsOnUserSwitched = false
@@ -122,6 +131,8 @@
     }
 
     private fun updateNotificationsOnUiModeChanged() {
+        colorUpdateLogger.logEvent("VCC.updateNotificationsOnUiModeChanged()",
+                "mode=" + mConfigurationController.nightModeName)
         log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
         traceSection("updateNotifOnUiModeChanged") {
             mPipeline?.allNotifs?.forEach { entry ->
@@ -131,6 +142,7 @@
     }
 
     private fun updateNotificationsOnDensityOrFontScaleChanged() {
+        colorUpdateLogger.logEvent("VCC.updateNotificationsOnDensityOrFontScaleChanged()")
         mPipeline?.allNotifs?.forEach { entry ->
             entry.onDensityOrFontScaleChanged()
             val exposedGuts = entry.areGutsExposed()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 16f18a3..f792898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -19,6 +19,7 @@
 import static android.graphics.PorterDuff.Mode.SRC_ATOP;
 
 import static com.android.systemui.Flags.notificationBackgroundTintOptimization;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
 
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
@@ -40,11 +41,13 @@
 
 import com.android.settingslib.Utils;
 import com.android.systemui.res.R;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
 import com.android.systemui.statusbar.notification.row.FooterViewButton;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.util.DrawableDumpKt;
 import com.android.systemui.util.DumpUtilsKt;
 
 import java.io.PrintWriter;
@@ -239,6 +242,10 @@
 
     @Override
     protected void onFinishInflate() {
+        ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+        if (colorUpdateLogger != null) {
+            colorUpdateLogger.logTriggerEvent("Footer.onFinishInflate()");
+        }
         super.onFinishInflate();
         mClearAllButton = (FooterViewButton) findSecondaryView();
         mManageOrHistoryButton = findViewById(R.id.manage_text);
@@ -348,6 +355,10 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
+        ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+        if (colorUpdateLogger != null) {
+            colorUpdateLogger.logTriggerEvent("Footer.onConfigurationChanged()");
+        }
         super.onConfigurationChanged(newConfig);
         updateColors();
         if (!FooterViewRefactor.isEnabled()) {
@@ -365,14 +376,17 @@
                 com.android.internal.R.attr.materialColorOnSurface);
         final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
         final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
+        final @ColorInt int scHigh;
         if (!notificationBackgroundTintOptimization()) {
-            final @ColorInt int scHigh = Utils.getColorAttrDefaultColor(mContext,
+            scHigh = Utils.getColorAttrDefaultColor(mContext,
                     com.android.internal.R.attr.materialColorSurfaceContainerHigh);
             if (scHigh != 0) {
                 final ColorFilter bgColorFilter = new PorterDuffColorFilter(scHigh, SRC_ATOP);
                 clearAllBg.setColorFilter(bgColorFilter);
                 manageBg.setColorFilter(bgColorFilter);
             }
+        } else {
+            scHigh = 0;
         }
         mClearAllButton.setBackground(clearAllBg);
         mClearAllButton.setTextColor(onSurface);
@@ -380,6 +394,13 @@
         mManageOrHistoryButton.setTextColor(onSurface);
         mSeenNotifsFooterTextView.setTextColor(onSurface);
         mSeenNotifsFooterTextView.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
+        ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+        if (colorUpdateLogger != null) {
+            colorUpdateLogger.logEvent("Footer.updateColors()",
+                    "textColor(onSurface)=" + hexColorString(onSurface)
+                            + " backgroundTint(surfaceContainerHigh)=" + hexColorString(scHigh)
+                            + " background=" + DrawableDumpKt.dumpToString(manageBg));
+        }
     }
 
     private void updateResources() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fca527f..7358034 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -88,7 +88,7 @@
     private boolean mActivated;
 
     private Interpolator mCurrentAppearInterpolator;
-    NotificationBackgroundView mBackgroundNormal;
+    protected NotificationBackgroundView mBackgroundNormal;
     private float mAnimationTranslationY;
     private boolean mDrawingAppearAnimation;
     private ValueAnimator mAppearAnimator;
@@ -142,6 +142,10 @@
         updateBackgroundTint();
     }
 
+    protected int getNormalBgColor() {
+        return mNormalColor;
+    }
+
     /**
      * @param width The actual width to apply to the background view.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index cc91ed3..d828ad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -21,6 +21,7 @@
 
 import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
+import static com.android.systemui.util.ColorUtilKt.hexColorString;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -85,6 +86,7 @@
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
 import com.android.systemui.statusbar.notification.NotificationFadeAware;
@@ -172,6 +174,7 @@
     private Optional<BubblesManager> mBubblesManagerOptional;
     private MetricsLogger mMetricsLogger;
     private NotificationChildrenContainerLogger mChildrenContainerLogger;
+    private ColorUpdateLogger mColorUpdateLogger;
     private NotificationDismissibilityProvider mDismissibilityProvider;
     private FeatureFlags mFeatureFlags;
     private int mIconTransformContentShift;
@@ -445,6 +448,7 @@
 
     /**
      * Sets animations running in the layouts of this row, including public, private, and children.
+     *
      * @param running whether the animations should be started running or stopped.
      */
     public void setAnimationRunning(boolean running) {
@@ -611,6 +615,12 @@
 
     private void updateBackgroundColorsOfSelf() {
         super.updateBackgroundColors();
+        if (mColorUpdateLogger.isEnabled()) {
+            mColorUpdateLogger.logNotificationEvent("ENR.updateBackgroundColorsOfSelf()",
+                    mLoggingKey,
+                    "normalBgColor=" + hexColorString(getNormalBgColor())
+                            + " background=" + mBackgroundNormal.toDumpString());
+        }
     }
 
     @Override
@@ -1389,7 +1399,7 @@
     }
 
     public void setContentBackground(int customBackgroundColor, boolean animate,
-                                     NotificationContentView notificationContentView) {
+            NotificationContentView notificationContentView) {
         if (getShowingLayout() == notificationContentView) {
             setTintColor(customBackgroundColor, animate);
         }
@@ -1458,7 +1468,7 @@
     }
 
     /**
-     * @return  if this entry should be kept in its parent during removal.
+     * @return if this entry should be kept in its parent during removal.
      */
     public boolean keepInParentForDismissAnimation() {
         return mKeepInParentForDismissAnimation;
@@ -1769,6 +1779,7 @@
             NotificationDismissibilityProvider dismissibilityProvider,
             MetricsLogger metricsLogger,
             NotificationChildrenContainerLogger childrenContainerLogger,
+            ColorUpdateLogger colorUpdateLogger,
             SmartReplyConstants smartReplyConstants,
             SmartReplyController smartReplyController,
             FeatureFlags featureFlags,
@@ -1807,6 +1818,7 @@
         mNotificationGutsManager = gutsManager;
         mMetricsLogger = metricsLogger;
         mChildrenContainerLogger = childrenContainerLogger;
+        mColorUpdateLogger = colorUpdateLogger;
         mDismissibilityProvider = dismissibilityProvider;
         mFeatureFlags = featureFlags;
     }
@@ -2265,7 +2277,7 @@
     }
 
     public Animator getTranslateViewAnimator(final float leftTarget,
-                                             AnimatorUpdateListener listener) {
+            AnimatorUpdateListener listener) {
         if (mTranslateAnim != null) {
             mTranslateAnim.cancel();
         }
@@ -2664,6 +2676,7 @@
             return getCollapsedHeight();
         }
     }
+
     /**
      * @return {@code true} if the notification can show it's heads up layout. This is mostly true
      * except for legacy use cases.
@@ -2833,7 +2846,7 @@
 
     @Override
     public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
-                                 long duration) {
+            long duration) {
         if (getVisibility() == GONE) {
             // If we are GONE, the hideSensitive parameter will not be calculated and always be
             // false, which is incorrect, let's wait until a real call comes in later.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 5614f3a..e59829b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -41,6 +41,7 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
@@ -86,6 +87,7 @@
     private final SystemClock mClock;
     private final String mAppName;
     private final String mNotificationKey;
+    private final ColorUpdateLogger mColorUpdateLogger;
     private final KeyguardBypassController mKeyguardBypassController;
     private final GroupMembershipManager mGroupMembershipManager;
     private final GroupExpansionManager mGroupExpansionManager;
@@ -200,6 +202,7 @@
             ActivatableNotificationViewController activatableNotificationViewController,
             RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
             MetricsLogger metricsLogger,
+            ColorUpdateLogger colorUpdateLogger,
             NotificationRowLogger logBufferLogger,
             NotificationChildrenContainerLogger childrenContainerLogger,
             NotificationListContainer listContainer,
@@ -256,6 +259,7 @@
         mDragController = dragController;
         mMetricsLogger = metricsLogger;
         mChildrenContainerLogger = childrenContainerLogger;
+        mColorUpdateLogger = colorUpdateLogger;
         mLogBufferLogger = logBufferLogger;
         mSmartReplyConstants = smartReplyConstants;
         mSmartReplyController = smartReplyController;
@@ -290,6 +294,7 @@
                 mDismissibilityProvider,
                 mMetricsLogger,
                 mChildrenContainerLogger,
+                mColorUpdateLogger,
                 mSmartReplyConstants,
                 mSmartReplyController,
                 mFeatureFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index ec8e5d7..ea9df9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import static com.android.systemui.Flags.notificationColorUpdateLogger;
+
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -54,8 +56,8 @@
 public abstract class ExpandableView extends FrameLayout implements Dumpable, Roundable {
     private static final String TAG = "ExpandableView";
     /** whether the dump() for this class should include verbose details */
-    protected static final boolean DUMP_VERBOSE =
-            Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
+    protected static final boolean DUMP_VERBOSE = Compile.IS_DEBUG
+            && (Log.isLoggable(TAG, Log.VERBOSE) || notificationColorUpdateLogger());
 
     private RoundableState mRoundableState = null;
     protected OnHeightChangedListener mOnHeightChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 7ea9b14..ed3a38d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -36,6 +36,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.res.R;
+import com.android.systemui.util.DrawableDumpKt;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -333,6 +334,16 @@
         pw.println("mActualHeight: " + mActualHeight);
         pw.println("mTintColor: " + hexColorString(mTintColor));
         pw.println("mRippleColor: " + hexColorString(mRippleColor));
-        pw.println("mBackground: " + mBackground);
+        pw.println("mBackground: " + DrawableDumpKt.dumpToString(mBackground));
+    }
+
+    /** create a concise dump of this view's colors */
+    public String toDumpString() {
+        return "<NotificationBackgroundView"
+                + " tintColor=" + hexColorString(mTintColor)
+                + " rippleColor=" + hexColorString(mRippleColor)
+                + " bgColor=" + DrawableDumpKt.getSolidColor(mBackground)
+                + ">";
+
     }
 }
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 933a780..7925a1c 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
@@ -99,6 +99,7 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
 import com.android.systemui.statusbar.notification.NotificationTransitionAnimatorController;
@@ -122,6 +123,7 @@
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.util.Assert;
+import com.android.systemui.util.ColorUtilKt;
 import com.android.systemui.util.DumpUtilsKt;
 
 import com.google.errorprone.annotations.CompileTimeConstant;
@@ -805,8 +807,8 @@
         updateBackgroundDimming();
         for (int i = 0; i < getChildCount(); i++) {
             View child = getChildAt(i);
-            if (child instanceof ActivatableNotificationView) {
-                ((ActivatableNotificationView) child).updateBackgroundColors();
+            if (child instanceof ActivatableNotificationView activatableView) {
+                activatableView.updateBackgroundColors();
             }
         }
     }
@@ -4595,6 +4597,13 @@
         final @ColorInt int onSurfaceVariant = Utils.getColorAttrDefaultColor(
                 mContext, com.android.internal.R.attr.materialColorOnSurfaceVariant);
 
+        ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance();
+        if (colorUpdateLogger != null) {
+            colorUpdateLogger.logEvent("NSSL.updateDecorViews()",
+                    "onSurface=" + ColorUtilKt.hexColorString(onSurface)
+                            + " onSurfaceVariant=" + ColorUtilKt.hexColorString(onSurfaceVariant));
+        }
+
         mSectionsManager.setHeaderForegroundColors(onSurface, onSurfaceVariant);
 
         if (mFooterView != null) {
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 78e6a79..d2ff266 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
@@ -96,6 +96,7 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -177,6 +178,7 @@
     private final ConfigurationController mConfigurationController;
     private final ZenModeController mZenModeController;
     private final MetricsLogger mMetricsLogger;
+    private final ColorUpdateLogger mColorUpdateLogger;
 
     private final DumpManager mDumpManager;
     private final FalsingCollector mFalsingCollector;
@@ -239,6 +241,7 @@
             new View.OnAttachStateChangeListener() {
                 @Override
                 public void onViewAttachedToWindow(View v) {
+                    mColorUpdateLogger.logTriggerEvent("NSSLC.onViewAttachedToWindow()");
                     mConfigurationController.addCallback(mConfigurationListener);
                     if (!FooterViewRefactor.isEnabled()) {
                         mZenModeController.addCallback(mZenModeControllerCallback);
@@ -254,6 +257,7 @@
 
                 @Override
                 public void onViewDetachedFromWindow(View v) {
+                    mColorUpdateLogger.logTriggerEvent("NSSLC.onViewDetachedFromWindow()");
                     mConfigurationController.removeCallback(mConfigurationListener);
                     if (!FooterViewRefactor.isEnabled()) {
                         mZenModeController.removeCallback(mZenModeControllerCallback);
@@ -332,12 +336,16 @@
 
         @Override
         public void onUiModeChanged() {
+            mColorUpdateLogger.logTriggerEvent("NSSLC.onUiModeChanged()",
+                    "mode=" + mConfigurationController.getNightModeName());
             mView.updateBgColor();
             mView.updateDecorViews();
         }
 
         @Override
         public void onThemeChanged() {
+            mColorUpdateLogger.logTriggerEvent("NSSLC.onThemeChanged()",
+                    "mode=" + mConfigurationController.getNightModeName());
             mView.updateCornerRadius();
             mView.updateBgColor();
             mView.updateDecorViews();
@@ -719,6 +727,7 @@
             ZenModeController zenModeController,
             NotificationLockscreenUserManager lockscreenUserManager,
             MetricsLogger metricsLogger,
+            ColorUpdateLogger colorUpdateLogger,
             DumpManager dumpManager,
             FalsingCollector falsingCollector,
             FalsingManager falsingManager,
@@ -773,6 +782,7 @@
         mZenModeController = zenModeController;
         mLockscreenUserManager = lockscreenUserManager;
         mMetricsLogger = metricsLogger;
+        mColorUpdateLogger = colorUpdateLogger;
         mDumpManager = dumpManager;
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mFalsingCollector = falsingCollector;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
index 4b8fb1e..20e8cac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt
@@ -18,7 +18,7 @@
 package com.android.systemui.statusbar.notification.stack.domain.interactor
 
 import android.content.Context
-import com.android.systemui.Flags.centralizedStatusBarDimensRefactor
+import com.android.systemui.Flags.centralizedStatusBarHeightFix
 import com.android.systemui.common.ui.data.repository.ConfigurationRepository
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
@@ -76,7 +76,7 @@
                             getDimensionPixelSize(R.dimen.notification_panel_margin_bottom),
                         marginTop = getDimensionPixelSize(R.dimen.notification_panel_margin_top),
                         marginTopLargeScreen =
-                            if (centralizedStatusBarDimensRefactor()) {
+                            if (centralizedStatusBarHeightFix()) {
                                 largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight()
                             } else {
                                 getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 6321820..7b50256 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -122,32 +122,31 @@
                     qsFullScreen,
                     isRemoteInputActive,
                     isShadeClosed ->
-                    // A pair of (visible, canAnimate)
                     when {
-                        !hasNotifications -> Pair(false, true)
+                        !hasNotifications -> VisibilityChange.HIDE_WITH_ANIMATION
                         // Hide the footer until the user setup is complete, to prevent access
                         // to settings (b/193149550).
-                        !isUserSetUp -> Pair(false, true)
+                        !isUserSetUp -> VisibilityChange.HIDE_WITH_ANIMATION
                         // Do not show the footer if the lockscreen is visible (incl. AOD),
                         // except if the shade is opened on top. See also b/219680200.
                         // Do not animate, as that makes the footer appear briefly when
                         // transitioning between the shade and keyguard.
-                        isShowingOnLockscreen -> Pair(false, false)
+                        isShowingOnLockscreen -> VisibilityChange.HIDE_WITHOUT_ANIMATION
                         // Do not show the footer if quick settings are fully expanded (except
                         // for the foldable split shade view). See b/201427195 && b/222699879.
-                        qsExpansion == 1f && qsFullScreen -> Pair(false, true)
+                        qsExpansion == 1f && qsFullScreen -> VisibilityChange.HIDE_WITH_ANIMATION
                         // Hide the footer if remote input is active (i.e. user is replying to a
                         // notification). See b/75984847.
-                        isRemoteInputActive -> Pair(false, true)
+                        isRemoteInputActive -> VisibilityChange.HIDE_WITH_ANIMATION
                         // Never show the footer if the shade is collapsed (e.g. when HUNing).
-                        isShadeClosed -> Pair(false, false)
-                        else -> Pair(true, true)
+                        isShadeClosed -> VisibilityChange.HIDE_WITHOUT_ANIMATION
+                        else -> VisibilityChange.SHOW_WITH_ANIMATION
                     }
                 }
                 .distinctUntilChanged(
                     // Equivalent unless visibility changes
-                    areEquivalent = { a: Pair<Boolean, Boolean>, b: Pair<Boolean, Boolean> ->
-                        a.first == b.first
+                    areEquivalent = { a: VisibilityChange, b: VisibilityChange ->
+                        a.visible == b.visible
                     }
                 )
                 // Should we animate the visibility change?
@@ -160,17 +159,24 @@
                             ::Pair
                         )
                         .onStart { emit(Pair(false, false)) }
-                ) { (visible, canAnimate), (isShadeFullyExpanded, animationsEnabled) ->
+                ) { visibilityChange, (isShadeFullyExpanded, animationsEnabled) ->
                     // Animate if the shade is interactive, but NOT on the lockscreen. Having
                     // animations enabled while on the lockscreen makes the footer appear briefly
                     // when transitioning between the shade and keyguard.
-                    val shouldAnimate = isShadeFullyExpanded && animationsEnabled && canAnimate
-                    AnimatableEvent(visible, shouldAnimate)
+                    val shouldAnimate =
+                        isShadeFullyExpanded && animationsEnabled && visibilityChange.canAnimate
+                    AnimatableEvent(visibilityChange.visible, shouldAnimate)
                 }
                 .toAnimatedValueFlow()
         }
     }
 
+    enum class VisibilityChange(val visible: Boolean, val canAnimate: Boolean) {
+        HIDE_WITHOUT_ANIMATION(visible = false, canAnimate = false),
+        HIDE_WITH_ANIMATION(visible = false, canAnimate = true),
+        SHOW_WITH_ANIMATION(visible = true, canAnimate = true)
+    }
+
     private val isShowingOnLockscreen: Flow<Boolean> by lazy {
         if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
             flowOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 6e8ad2e..dea9416 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -159,6 +159,15 @@
     override fun isLayoutRtl(): Boolean {
         return layoutDirection == LAYOUT_DIRECTION_RTL
     }
+
+    override fun getNightModeName(): String {
+        return when (uiMode and Configuration.UI_MODE_NIGHT_MASK) {
+            Configuration.UI_MODE_NIGHT_YES -> "night"
+            Configuration.UI_MODE_NIGHT_NO -> "day"
+            Configuration.UI_MODE_NIGHT_UNDEFINED -> "undefined"
+            else -> "err"
+        }
+    }
 }
 
 // This could be done with a Collection.filter and Collection.forEach, but Collection.filter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index db55da7..0adc1b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor;
+import static com.android.systemui.Flags.centralizedStatusBarHeightFix;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInScale;
 import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
@@ -169,7 +169,7 @@
         mStatusViewBottomMargin =
                 res.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin);
         mSplitShadeTopNotificationsMargin =
-                centralizedStatusBarDimensRefactor()
+                centralizedStatusBarHeightFix()
                         ? LargeScreenHeaderHelper.getLargeScreenHeaderHeight(context)
                         : res.getDimensionPixelSize(R.dimen.large_screen_shade_header_height);
         mSplitShadeTargetTopMargin =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7691459..302bdcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor;
+import static com.android.systemui.Flags.centralizedStatusBarHeightFix;
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
 import static com.android.systemui.util.Utils.getStatusBarHeaderHeightKeyguard;
 
@@ -131,7 +131,7 @@
         mUserSwitcherContainer = findViewById(R.id.user_switcher_container);
         mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot);
         loadDimens();
-        if (!centralizedStatusBarDimensRefactor()) {
+        if (!centralizedStatusBarHeightFix()) {
             setGravity(Gravity.CENTER_VERTICAL);
         }
     }
@@ -311,7 +311,7 @@
         final int minRight = (!isLayoutRtl() && mIsPrivacyDotEnabled)
                 ? Math.max(mMinDotWidth, mPadding.right) : mPadding.right;
 
-        int top = centralizedStatusBarDimensRefactor() ? waterfallTop + mPadding.top : waterfallTop;
+        int top = centralizedStatusBarHeightFix() ? waterfallTop + mPadding.top : waterfallTop;
         setPadding(minLeft, top, minRight, 0);
     }
 
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 6f78604..d2e36b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -733,7 +733,8 @@
 
         if (mPanelExpansionFraction != panelExpansionFraction) {
             if (panelExpansionFraction != 0f
-                    && mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
+                    && mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()
+                    && mState != ScrimState.UNLOCKED) {
                 mAnimatingPanelExpansionOnUnlock = true;
             } else if (panelExpansionFraction == 0f) {
                 mAnimatingPanelExpansionOnUnlock = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 1414150..2c1780d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -158,7 +158,15 @@
     @Override
     public void showNotification(@NonNull NotificationEntry entry) {
         mLogger.logShowNotification(entry);
-        addEntry(entry);
+
+        // Add new entry and begin managing it
+        HeadsUpEntry headsUpEntry = createHeadsUpEntry();
+        headsUpEntry.setEntry(entry);
+        mHeadsUpEntryMap.put(entry.getKey(), headsUpEntry);
+        onEntryAdded(headsUpEntry);
+        entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        entry.setIsHeadsUpEntry(true);
+
         updateNotification(entry.getKey(), true /* shouldHeadsUpAgain */);
         entry.setInterruption();
     }
@@ -319,19 +327,6 @@
     }
 
     /**
-     * Add a new entry and begin managing it.
-     * @param entry the entry to add
-     */
-    protected final void addEntry(@NonNull NotificationEntry entry) {
-        HeadsUpEntry headsUpEntry = createHeadsUpEntry();
-        headsUpEntry.setEntry(entry);
-        mHeadsUpEntryMap.put(entry.getKey(), headsUpEntry);
-        onEntryAdded(headsUpEntry);
-        entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-        entry.setIsHeadsUpEntry(true);
-    }
-
-    /**
      * Manager-specific logic that should occur when an entry is added.
      * @param headsUpEntry entry added
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index b2ef818..cec77c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -33,6 +33,9 @@
     /** Query the current configuration's layout direction */
     boolean isLayoutRtl();
 
+    /** Logging only; Query the current configuration's night mode name */
+    String getNightModeName();
+
     interface ConfigurationListener {
         default void onConfigChanged(Configuration newConfig) {}
         default void onDensityOrFontScaleChanged() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index df210b0..600005b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.android.systemui.Flags.registerZenModeContentObserverBackground;
+
 import android.app.AlarmManager;
 import android.app.Flags;
 import android.app.NotificationManager;
@@ -45,6 +47,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.settings.UserTracker;
@@ -104,6 +107,7 @@
     public ZenModeControllerImpl(
             Context context,
             @Main Handler handler,
+            @Background Handler bgHandler,
             BroadcastDispatcher broadcastDispatcher,
             DumpManager dumpManager,
             GlobalSettings globalSettings,
@@ -134,9 +138,18 @@
             }
         };
         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        globalSettings.registerContentObserver(Global.ZEN_MODE, modeContentObserver);
+        if (registerZenModeContentObserverBackground()) {
+            bgHandler.post(() -> {
+                globalSettings.registerContentObserver(Global.ZEN_MODE, modeContentObserver);
+                globalSettings.registerContentObserver(Global.ZEN_MODE_CONFIG_ETAG,
+                        configContentObserver);
+            });
+        } else {
+            globalSettings.registerContentObserver(Global.ZEN_MODE, modeContentObserver);
+            globalSettings.registerContentObserver(Global.ZEN_MODE_CONFIG_ETAG,
+                    configContentObserver);
+        }
         updateZenMode(getModeSettingValueFromProvider());
-        globalSettings.registerContentObserver(Global.ZEN_MODE_CONFIG_ETAG, configContentObserver);
         updateZenModeConfig();
         updateConsolidatedNotificationPolicy();
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 585ab72..44c684c 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -815,7 +815,7 @@
                 ? () -> {}
                 : () -> {
                     Log.d(TAG, "ThemeHomeDelay: ThemeOverlayController ready");
-                    mActivityManager.setThemeOverlayReady(true);
+                    mActivityManager.setThemeOverlayReady(currentUser);
                 };
 
         if (colorSchemeIsApplied(managedProfiles)) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/DrawableDump.kt b/packages/SystemUI/src/com/android/systemui/util/DrawableDump.kt
new file mode 100644
index 0000000..0c079a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DrawableDump.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import android.content.res.ColorStateList
+import android.graphics.BlendMode
+import android.graphics.BlendModeColorFilter
+import android.graphics.ColorFilter
+import android.graphics.LightingColorFilter
+import android.graphics.PorterDuffColorFilter
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.DrawableWrapper
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.LayerDrawable
+import android.graphics.drawable.RippleDrawable
+import android.util.Log
+
+fun dumpToString(drawable: Drawable?): String =
+    if (Compile.IS_DEBUG) StringBuilder().appendDrawable(drawable).toString()
+    else drawable.toString()
+
+fun getSolidColor(drawable: Drawable?): String =
+    if (Compile.IS_DEBUG) hexColorString(getSolidColors(drawable)?.defaultColor)
+    else if (drawable == null) "null" else "?"
+
+private fun getSolidColors(drawable: Drawable?): ColorStateList? {
+    return when (drawable) {
+        is GradientDrawable -> {
+            return drawable.getStateField<ColorStateList>("mSolidColors")
+        }
+        is LayerDrawable -> {
+            for (iLayer in 0 until drawable.numberOfLayers) {
+                getSolidColors(drawable.getDrawable(iLayer))?.let {
+                    return it
+                }
+            }
+            null
+        }
+        is DrawableWrapper -> {
+            return getSolidColors(drawable.drawable)
+        }
+        else -> null
+    }
+}
+
+private fun StringBuilder.appendDrawable(drawable: Drawable?): StringBuilder {
+    if (drawable == null) {
+        append("null")
+        return this
+    }
+    append("<")
+    append(drawable.javaClass.simpleName)
+
+    drawable.getStateField<ColorStateList>("mTint", fieldRequired = false)?.let {
+        append(" tint=")
+        appendColors(it)
+        append(" blendMode=")
+        append(drawable.getStateField<BlendMode>("mBlendMode"))
+    }
+    drawable.colorFilter
+        ?.takeUnless { drawable is DrawableWrapper }
+        ?.let {
+            append(" colorFilter=")
+            appendColorFilter(it)
+        }
+    when (drawable) {
+        is DrawableWrapper -> {
+            append(" wrapped=")
+            appendDrawable(drawable.drawable)
+        }
+        is LayerDrawable -> {
+            if (drawable is RippleDrawable) {
+                drawable.getStateField<ColorStateList>("mColor")?.let {
+                    append(" color=")
+                    appendColors(it)
+                }
+                drawable.effectColor?.let {
+                    append(" effectColor=")
+                    appendColors(it)
+                }
+            }
+            append(" layers=[")
+            for (iLayer in 0 until drawable.numberOfLayers) {
+                if (iLayer != 0) append(", ")
+                appendDrawable(drawable.getDrawable(iLayer))
+            }
+            append("]")
+        }
+        is GradientDrawable -> {
+            drawable
+                .getStateField<Int>("mShape")
+                ?.takeIf { it != 0 }
+                ?.let {
+                    append(" shape=")
+                    append(it)
+                }
+            drawable.getStateField<ColorStateList>("mSolidColors")?.let {
+                append(" solidColors=")
+                appendColors(it)
+            }
+            drawable.getStateField<ColorStateList>("mStrokeColors")?.let {
+                append(" strokeColors=")
+                appendColors(it)
+            }
+            drawable.colors?.let {
+                append(" gradientColors=[")
+                it.forEachIndexed { iColor, color ->
+                    if (iColor != 0) append(", ")
+                    append(hexColorString(color))
+                }
+                append("]")
+            }
+        }
+    }
+    append(">")
+    return this
+}
+
+private inline fun <reified T> Drawable.getStateField(
+    name: String,
+    fieldRequired: Boolean = true
+): T? {
+    val state = this.constantState ?: return null
+    val clazz = state.javaClass
+    return try {
+        val field = clazz.getDeclaredField(name)
+        field.isAccessible = true
+        field.get(state) as T?
+    } catch (ex: Exception) {
+        if (fieldRequired) {
+            Log.w(TAG, "Missing ${clazz.simpleName}.$name: ${T::class.simpleName}", ex)
+        } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "Missing ${clazz.simpleName}.$name: ${T::class.simpleName} ($ex)")
+        }
+        null
+    }
+}
+
+private fun Appendable.appendColors(colorStateList: ColorStateList?) {
+    if (colorStateList == null) {
+        append("null")
+        return
+    }
+    val colors = colorStateList.colors
+    if (colors.size == 1) {
+        append(hexColorString(colors[0]))
+        return
+    }
+    append("<ColorStateList size=")
+    append(colors.size.toString())
+    append(" default=")
+    append(hexColorString(colorStateList.defaultColor))
+    append(">")
+}
+
+private fun Appendable.appendColorFilter(colorFilter: ColorFilter?) {
+    if (colorFilter == null) {
+        append("null")
+        return
+    }
+    append("<")
+    append(colorFilter.javaClass.simpleName)
+    when (colorFilter) {
+        is PorterDuffColorFilter -> {
+            append(" color=")
+            append(hexColorString(colorFilter.color))
+            append(" mode=")
+            append(colorFilter.mode.toString())
+        }
+        is BlendModeColorFilter -> {
+            append(" color=")
+            append(hexColorString(colorFilter.color))
+            append(" mode=")
+            append(colorFilter.mode.toString())
+        }
+        is LightingColorFilter -> {
+            append(" multiply=")
+            append(hexColorString(colorFilter.colorMultiply))
+            append(" add=")
+            append(hexColorString(colorFilter.colorAdd))
+        }
+        else -> append(" unhandled")
+    }
+    append(">")
+}
+
+private const val TAG = "DrawableDump"
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt
new file mode 100644
index 0000000..e17274c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/FlowDumper.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import android.util.IndentingPrintWriter
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.printCollection
+import java.io.PrintWriter
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flow
+
+/**
+ * An interface which gives the implementing type flow extension functions which will register a
+ * given flow as a field in the Dumpable.
+ */
+interface FlowDumper : Dumpable {
+    /**
+     * Include the last emitted value of this Flow whenever it is being collected. Remove its value
+     * when collection ends.
+     *
+     * @param dumpName the name to use for this field in the dump output
+     */
+    fun <T> Flow<T>.dumpWhileCollecting(dumpName: String): Flow<T>
+
+    /**
+     * Include the [SharedFlow.replayCache] for this Flow in the dump.
+     *
+     * @param dumpName the name to use for this field in the dump output
+     */
+    fun <T, F : SharedFlow<T>> F.dumpReplayCache(dumpName: String): F
+
+    /**
+     * Include the [StateFlow.value] for this Flow in the dump.
+     *
+     * @param dumpName the name to use for this field in the dump output
+     */
+    fun <T, F : StateFlow<T>> F.dumpValue(dumpName: String): F
+
+    /** The default [Dumpable.dump] implementation which just calls [dumpFlows] */
+    override fun dump(pw: PrintWriter, args: Array<out String>) = dumpFlows(pw.asIndenting())
+
+    /** Dump all the values from any registered / active Flows. */
+    fun dumpFlows(pw: IndentingPrintWriter)
+}
+
+/**
+ * An implementation of [FlowDumper]. This be extended directly, or can be used to implement
+ * [FlowDumper] by delegation.
+ *
+ * @param dumpManager if provided, this will be used by the [FlowDumperImpl] to register and
+ *   unregister itself when there is something to dump.
+ * @param tag a static name by which this [FlowDumperImpl] is registered. If not provided, this
+ *   class's name will be used. If you're implementing by delegation, you probably want to provide
+ *   this tag to get a meaningful dumpable name.
+ */
+open class FlowDumperImpl(private val dumpManager: DumpManager?, tag: String? = null) : FlowDumper {
+    private val stateFlowMap = ConcurrentHashMap<String, StateFlow<*>>()
+    private val sharedFlowMap = ConcurrentHashMap<String, SharedFlow<*>>()
+    private val flowCollectionMap = ConcurrentHashMap<Pair<String, String>, Any>()
+    override fun dumpFlows(pw: IndentingPrintWriter) {
+        pw.printCollection("StateFlow (value)", stateFlowMap.toSortedMap().entries) { (key, flow) ->
+            append(key).append('=').println(flow.value)
+        }
+        pw.printCollection("SharedFlow (replayCache)", sharedFlowMap.toSortedMap().entries) {
+            (key, flow) ->
+            append(key).append('=').println(flow.replayCache)
+        }
+        val comparator = compareBy<Pair<String, String>> { it.first }.thenBy { it.second }
+        pw.printCollection("Flow (latest)", flowCollectionMap.toSortedMap(comparator).entries) {
+            (pair, value) ->
+            append(pair.first).append('=').println(value)
+        }
+    }
+
+    private val Any.idString: String
+        get() = Integer.toHexString(System.identityHashCode(this))
+
+    override fun <T> Flow<T>.dumpWhileCollecting(dumpName: String): Flow<T> = flow {
+        val mapKey = dumpName to idString
+        try {
+            collect {
+                flowCollectionMap[mapKey] = it ?: "null"
+                updateRegistration(required = true)
+                emit(it)
+            }
+        } finally {
+            flowCollectionMap.remove(mapKey)
+            updateRegistration(required = false)
+        }
+    }
+
+    override fun <T, F : StateFlow<T>> F.dumpValue(dumpName: String): F {
+        stateFlowMap[dumpName] = this
+        return this
+    }
+
+    override fun <T, F : SharedFlow<T>> F.dumpReplayCache(dumpName: String): F {
+        sharedFlowMap[dumpName] = this
+        return this
+    }
+
+    private val dumpManagerName = tag ?: "[$idString] ${javaClass.simpleName}"
+    private var registered = AtomicBoolean(false)
+    private fun updateRegistration(required: Boolean) {
+        if (dumpManager == null) return
+        if (required && registered.get()) return
+        synchronized(registered) {
+            val shouldRegister =
+                stateFlowMap.isNotEmpty() ||
+                    sharedFlowMap.isNotEmpty() ||
+                    flowCollectionMap.isNotEmpty()
+            val wasRegistered = registered.getAndSet(shouldRegister)
+            if (wasRegistered != shouldRegister) {
+                if (shouldRegister) {
+                    dumpManager.registerCriticalDumpable(dumpManagerName, this)
+                } else {
+                    dumpManager.unregisterDumpable(dumpManagerName)
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index e832506..15e0965 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -356,6 +356,12 @@
                         // TODO(b/278084491): update sysui state for changes on other displays
                     }
                 }, mSysUiMainExecutor);
+        mCommandQueue.addCallback(new CommandQueue.Callbacks() {
+            @Override
+            public void enterDesktop(int displayId) {
+                desktopMode.enterDesktop(displayId);
+            }
+        });
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
index 4d3243a..edb910a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
@@ -22,8 +22,10 @@
 import static org.mockito.Mockito.when;
 
 import android.content.pm.PackageManager;
+import android.os.Handler;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 
@@ -57,17 +59,22 @@
     private ActivityStarter mActivityStarter;
     private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
     private DumpManager mDumpManager = new DumpManager();
-
+    private Handler mHandler;
+    private Handler mBgHandler;
     private KeyguardSliceViewController mController;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        TestableLooper testableLooper = TestableLooper.get(this);
+        assert testableLooper != null;
+        mHandler = new Handler(testableLooper.getLooper());
+        mBgHandler = new Handler(testableLooper.getLooper());
         when(mView.isAttachedToWindow()).thenReturn(true);
         when(mView.getContext()).thenReturn(mContext);
-        mController = new KeyguardSliceViewController(
-                mView, mActivityStarter, mConfigurationController,
-                mTunerService, mDumpManager, mDisplayTracker);
+        mController = new KeyguardSliceViewController(mHandler, mBgHandler, mView,
+                mActivityStarter, mConfigurationController, mTunerService, mDumpManager,
+                mDisplayTracker);
         mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
index 5eda2b2..569e064 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
@@ -89,6 +89,16 @@
         }
     }
 
+    @Test
+    fun testParentProfile() {
+        for (value in listOf(12, 8, 4)) {
+            whenever(userManager.getProfileParent(eq(USER_ID)))
+                .thenReturn(UserInfo(value, "test", 0))
+
+            assertThat(interactor.getParentProfileIdOrSelfId(USER_ID)).isEqualTo(value)
+        }
+    }
+
     @Test fun pinCredentialWhenGood() = pinCredential(goodCredential())
 
     @Test fun pinCredentialWhenBad() = pinCredential(badCredential())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 1a6da76..915522d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -53,11 +53,9 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.testKosmos
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
@@ -103,8 +101,6 @@
     private lateinit var underTest: CustomizationProvider
     private lateinit var testScope: TestScope
 
-    private val kosmos = testKosmos()
-
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -189,7 +185,6 @@
                                 },
                         )
                         .keyguardInteractor,
-                shadeInteractor = kosmos.shadeInteractor,
                 lockPatternUtils = lockPatternUtils,
                 keyguardStateController = keyguardStateController,
                 userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 45b2a42..d2a8444 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -46,9 +46,7 @@
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.testKosmos
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
@@ -244,8 +242,6 @@
     private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
     private lateinit var userTracker: UserTracker
 
-    private val kosmos = testKosmos()
-
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -315,7 +311,6 @@
                             featureFlags = featureFlags,
                         )
                         .keyguardInteractor,
-                shadeInteractor = kosmos.shadeInteractor,
                 lockPatternUtils = lockPatternUtils,
                 keyguardStateController = keyguardStateController,
                 userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 7290863..2ec2fe3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -54,7 +54,6 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -219,7 +218,6 @@
                 quickAffordanceInteractor =
                     KeyguardQuickAffordanceInteractor(
                         keyguardInteractor = keyguardInteractor,
-                        shadeInteractor = kosmos.shadeInteractor,
                         lockPatternUtils = lockPatternUtils,
                         keyguardStateController = keyguardStateController,
                         userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
index eded4dcb..18a34ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
@@ -264,14 +264,12 @@
         whenever(lockscreenToPrimaryBouncerTransitionViewModel.shortcutsAlpha)
             .thenReturn(emptyFlow())
         whenever(shadeInteractor.qsExpansion).thenReturn(intendedShadeAlphaMutableStateFlow)
-        whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f))
 
         underTest =
             KeyguardQuickAffordancesCombinedViewModel(
                 quickAffordanceInteractor =
                     KeyguardQuickAffordanceInteractor(
                         keyguardInteractor = keyguardInteractor,
-                        shadeInteractor = shadeInteractor,
                         lockPatternUtils = lockPatternUtils,
                         keyguardStateController = keyguardStateController,
                         userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 83f8f18..0683321 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -30,7 +30,7 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.qs.tiles.dialog.InternetDialogFactory
+import com.android.systemui.qs.tiles.dialog.InternetDialogManager
 import com.android.systemui.statusbar.connectivity.AccessPointController
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
@@ -83,7 +83,7 @@
     @Mock private lateinit var sbStateController: StatusBarStateController
     @Mock private lateinit var activityStarter: ActivityStarter
     @Mock private lateinit var logger: QSLogger
-    @Mock private lateinit var dialogFactory: InternetDialogFactory
+    @Mock private lateinit var dialogManager: InternetDialogManager
     @Mock private lateinit var accessPointController: AccessPointController
 
     @Before
@@ -118,7 +118,7 @@
                 activityStarter,
                 logger,
                 viewModel,
-                dialogFactory,
+                dialogManager,
                 accessPointController
             )
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
index c1f1964..288facc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
@@ -17,7 +17,6 @@
 package com.android.systemui.qs.tiles;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -38,7 +37,7 @@
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
+import com.android.systemui.qs.tiles.dialog.InternetDialogManager;
 import com.android.systemui.statusbar.connectivity.AccessPointController;
 import com.android.systemui.statusbar.connectivity.IconState;
 import com.android.systemui.statusbar.connectivity.NetworkController;
@@ -63,7 +62,7 @@
     @Mock
     private AccessPointController mAccessPointController;
     @Mock
-    private InternetDialogFactory mInternetDialogFactory;
+    private InternetDialogManager mInternetDialogManager;
     @Mock
     private QsEventLogger mUiEventLogger;
 
@@ -89,7 +88,7 @@
             mock(QSLogger.class),
             mNetworkController,
             mAccessPointController,
-            mInternetDialogFactory
+                mInternetDialogManager
         );
 
         mTile.initialize();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
index 077ec4b..74f50df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
@@ -5,7 +5,6 @@
 import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
 import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GREAT;
 import static android.telephony.SignalStrength.SIGNAL_STRENGTH_POOR;
-
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource;
 import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
@@ -13,9 +12,7 @@
 import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX;
 import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN;
 import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -101,7 +98,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class InternetDialogControllerTest extends SysuiTestCase {
+public class InternetDialogDelegateControllerTest extends SysuiTestCase {
 
     private static final int SUB_ID = 1;
     private static final int SUB_ID2 = 2;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
similarity index 80%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
index c9e6274..db9f5cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
@@ -1,9 +1,7 @@
 package com.android.systemui.qs.tiles.dialog;
 
 import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -34,6 +32,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.DialogTransitionAnimator;
 import com.android.systemui.res.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -55,7 +54,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class InternetDialogTest extends SysuiTestCase {
+public class InternetDialogDelegateTest extends SysuiTestCase {
 
     private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
     private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary";
@@ -78,9 +77,13 @@
     private KeyguardStateController mKeyguard;
     @Mock
     private DialogTransitionAnimator mDialogTransitionAnimator;
+    @Mock
+    private SystemUIDialog.Factory mSystemUIDialogFactory;
+    @Mock
+    private SystemUIDialog mSystemUIDialog;
 
     private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
-    private InternetDialog mInternetDialog;
+    private InternetDialogDelegate mInternetDialogDelegate;
     private View mDialogView;
     private View mSubTitle;
     private LinearLayout mEthernet;
@@ -117,21 +120,30 @@
                 .spyStatic(WifiEnterpriseRestrictionUtils.class)
                 .startMocking();
         when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
-
+        when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class)))
+                .thenReturn(mSystemUIDialog);
         createInternetDialog();
     }
 
     private void createInternetDialog() {
-        mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
-                mInternetDialogController, true, true, true, mock(UiEventLogger.class),
-                mDialogTransitionAnimator, mHandler,
-                mBgExecutor, mKeyguard);
-        mInternetDialog.mAdapter = mInternetAdapter;
-        mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
-        mInternetDialog.mWifiEntriesCount = mWifiEntries.size();
-        mInternetDialog.show();
+        mInternetDialogDelegate = new InternetDialogDelegate(
+                mContext,
+                mock(InternetDialogManager.class),
+                mInternetDialogController,
+                true,
+                true,
+                true,
+                mock(UiEventLogger.class),
+                mDialogTransitionAnimator,
+                mHandler,
+                mBgExecutor,
+                mKeyguard,
+                mSystemUIDialogFactory);
+        mInternetDialogDelegate.mAdapter = mInternetAdapter;
+        mInternetDialogDelegate.mConnectedWifiEntry = mInternetWifiEntry;
+        mInternetDialogDelegate.mWifiEntriesCount = mWifiEntries.size();
 
-        mDialogView = mInternetDialog.mDialogView;
+        mDialogView = mInternetDialogDelegate.mDialogView;
         mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
         mEthernet = mDialogView.requireViewById(R.id.ethernet_layout);
         mMobileDataLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
@@ -148,7 +160,7 @@
 
     @After
     public void tearDown() {
-        mInternetDialog.dismissDialog();
+        mInternetDialogDelegate.dismissDialog();
         mMockitoSession.finishMocking();
     }
 
@@ -160,9 +172,9 @@
 
     @Test
     public void hideWifiViews_WifiViewsGone() {
-        mInternetDialog.hideWifiViews();
+        mInternetDialogDelegate.hideWifiViews();
 
-        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        assertThat(mInternetDialogDelegate.mIsProgressBarVisible).isFalse();
         assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
         assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
@@ -173,7 +185,7 @@
     public void updateDialog_withApmOn_internetDialogSubTitleGone() {
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
     }
@@ -182,7 +194,7 @@
     public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
     }
@@ -192,7 +204,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
         when(mInternetDialogController.hasEthernet()).thenReturn(true);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
     }
@@ -202,7 +214,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
         when(mInternetDialogController.hasEthernet()).thenReturn(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
     }
@@ -212,7 +224,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
         when(mInternetDialogController.hasEthernet()).thenReturn(true);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
     }
@@ -222,7 +234,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
         when(mInternetDialogController.hasEthernet()).thenReturn(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
     }
@@ -234,7 +246,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
         when(mInternetDialogController.hasActiveSubId()).thenReturn(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
     }
@@ -246,7 +258,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
         when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
 
@@ -255,7 +267,7 @@
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
         when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
     }
@@ -265,7 +277,7 @@
         when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
     }
@@ -274,10 +286,10 @@
     public void updateDialog_apmOnAndWifiOnHasCarrierNetwork_showAirplaneSummary() {
         when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialog.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
         doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -287,10 +299,10 @@
     public void updateDialog_apmOffAndWifiOnHasCarrierNetwork_notShowApmSummary() {
         when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        mInternetDialog.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
         doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
     }
@@ -300,7 +312,7 @@
         when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
     }
@@ -310,7 +322,7 @@
         when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
     }
@@ -322,7 +334,7 @@
         when(mInternetDialogController.isMobileDataEnabled()).thenReturn(true);
         mMobileToggleSwitch.setChecked(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileToggleSwitch.isChecked()).isTrue();
     }
@@ -334,20 +346,20 @@
         when(mInternetDialogController.isMobileDataEnabled()).thenReturn(false);
         mMobileToggleSwitch.setChecked(false);
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mMobileToggleSwitch.isChecked()).isFalse();
     }
 
     @Test
     public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
-        mInternetDialog.dismissDialog();
+        mInternetDialogDelegate.dismissDialog();
         doReturn(true).when(mInternetDialogController).hasActiveSubId();
         createInternetDialog();
         // The preconditions WiFi ON and Internet WiFi are already in setUp()
         doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
 
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
         LinearLayout secondaryLayout = mDialogView.requireViewById(
@@ -358,10 +370,10 @@
     @Test
     public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
         // The precondition WiFi ON is already in setUp()
-        mInternetDialog.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
         doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
     }
@@ -369,10 +381,10 @@
     @Test
     public void updateDialog_wifiOnAndNoWifiEntry_showWifiListAndSeeAllArea() {
         // The precondition WiFi ON is already in setUp()
-        mInternetDialog.mConnectedWifiEntry = null;
-        mInternetDialog.mWifiEntriesCount = 0;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mWifiEntriesCount = 0;
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
         // Show a blank block to fix the dialog height even if there is no WiFi list
@@ -384,10 +396,10 @@
     @Test
     public void updateDialog_wifiOnAndOneWifiEntry_showWifiListAndSeeAllArea() {
         // The precondition WiFi ON is already in setUp()
-        mInternetDialog.mConnectedWifiEntry = null;
-        mInternetDialog.mWifiEntriesCount = 1;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mWifiEntriesCount = 1;
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
         // Show a blank block to fix the dialog height even if there is no WiFi list
@@ -399,9 +411,9 @@
     @Test
     public void updateDialog_wifiOnAndHasConnectedWifi_showAllWifiAndSeeAllArea() {
         // The preconditions WiFi ON and WiFi entries are already in setUp()
-        mInternetDialog.mWifiEntriesCount = 0;
+        mInternetDialogDelegate.mWifiEntriesCount = 0;
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
         // Show a blank block to fix the dialog height even if there is no WiFi list
@@ -413,11 +425,11 @@
     @Test
     public void updateDialog_wifiOnAndHasMaxWifiList_showWifiListAndSeeAll() {
         // The preconditions WiFi ON and WiFi entries are already in setUp()
-        mInternetDialog.mConnectedWifiEntry = null;
-        mInternetDialog.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT;
-        mInternetDialog.mHasMoreWifiEntries = true;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT;
+        mInternetDialogDelegate.mHasMoreWifiEntries = true;
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
         assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
@@ -428,10 +440,10 @@
     @Test
     public void updateDialog_wifiOnAndHasBothWifiEntry_showBothWifiEntryAndSeeAll() {
         // The preconditions WiFi ON and WiFi entries are already in setUp()
-        mInternetDialog.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT - 1;
-        mInternetDialog.mHasMoreWifiEntries = true;
+        mInternetDialogDelegate.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT - 1;
+        mInternetDialogDelegate.mHasMoreWifiEntries = true;
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
@@ -443,9 +455,9 @@
     public void updateDialog_deviceLockedAndNoConnectedWifi_showWifiToggle() {
         // The preconditions WiFi entries are already in setUp()
         when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-        mInternetDialog.mConnectedWifiEntry = null;
+        mInternetDialogDelegate.mConnectedWifiEntry = null;
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         // Show WiFi Toggle without background
         assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
@@ -461,7 +473,7 @@
         // The preconditions WiFi ON and WiFi entries are already in setUp()
         when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         // Show WiFi Toggle with highlight background
         assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
@@ -474,11 +486,11 @@
 
     @Test
     public void updateDialog_disallowChangeWifiState_disableWifiSwitch() {
-        mInternetDialog.dismissDialog();
+        mInternetDialogDelegate.dismissDialog();
         when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(false);
         createInternetDialog();
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         // Disable Wi-Fi switch and show restriction message in summary.
         assertThat(mWifiToggleSwitch.isEnabled()).isFalse();
@@ -488,11 +500,11 @@
 
     @Test
     public void updateDialog_allowChangeWifiState_enableWifiSwitch() {
-        mInternetDialog.dismissDialog();
+        mInternetDialogDelegate.dismissDialog();
         when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
         createInternetDialog();
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         // Enable Wi-Fi switch and hide restriction message in summary.
         assertThat(mWifiToggleSwitch.isEnabled()).isTrue();
@@ -501,14 +513,14 @@
 
     @Test
     public void updateDialog_showSecondaryDataSub() {
-        mInternetDialog.dismissDialog();
+        mInternetDialogDelegate.dismissDialog();
         doReturn(1).when(mInternetDialogController).getActiveAutoSwitchNonDdsSubId();
         doReturn(true).when(mInternetDialogController).hasActiveSubId();
         doReturn(false).when(mInternetDialogController).isAirplaneModeEnabled();
         createInternetDialog();
 
         clearInvocations(mInternetDialogController);
-        mInternetDialog.updateDialog(true);
+        mInternetDialogDelegate.updateDialog(true);
 
         LinearLayout primaryLayout = mDialogView.requireViewById(
                 R.id.mobile_network_layout);
@@ -523,7 +535,7 @@
         ArgumentCaptor<AlertDialog> dialogArgumentCaptor =
                 ArgumentCaptor.forClass(AlertDialog.class);
         verify(mDialogTransitionAnimator).showFromDialog(dialogArgumentCaptor.capture(),
-                eq(mInternetDialog), eq(null), eq(false));
+                eq(mSystemUIDialog), eq(null), eq(false));
         AlertDialog dialog = dialogArgumentCaptor.getValue();
         dialog.show();
         dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
@@ -541,7 +553,7 @@
     public void updateDialog_wifiOn_hideWifiScanNotify() {
         // The preconditions WiFi ON and WiFi entries are already in setUp()
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
     }
@@ -551,7 +563,7 @@
         when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
         when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
     }
@@ -562,7 +574,7 @@
         when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
         when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
     }
@@ -573,7 +585,7 @@
         when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
         when(mInternetDialogController.isDeviceLocked()).thenReturn(false);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE);
         TextView wifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text);
@@ -586,7 +598,7 @@
         when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
         mWifiToggleSwitch.setChecked(true);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mWifiToggleSwitch.isChecked()).isFalse();
     }
@@ -596,7 +608,7 @@
         when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
         mWifiToggleSwitch.setChecked(false);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
         assertThat(mWifiToggleSwitch.isChecked()).isTrue();
     }
@@ -611,20 +623,20 @@
 
     @Test
     public void onWifiScan_isScanTrue_setProgressBarVisibleTrue() {
-        mInternetDialog.mIsProgressBarVisible = false;
+        mInternetDialogDelegate.mIsProgressBarVisible = false;
 
-        mInternetDialog.onWifiScan(true);
+        mInternetDialogDelegate.onWifiScan(true);
 
-        assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
+        assertThat(mInternetDialogDelegate.mIsProgressBarVisible).isTrue();
     }
 
     @Test
     public void onWifiScan_isScanFalse_setProgressBarVisibleFalse() {
-        mInternetDialog.mIsProgressBarVisible = true;
+        mInternetDialogDelegate.mIsProgressBarVisible = true;
 
-        mInternetDialog.onWifiScan(false);
+        mInternetDialogDelegate.onWifiScan(false);
 
-        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        assertThat(mInternetDialogDelegate.mIsProgressBarVisible).isFalse();
     }
 
     @Test
@@ -633,42 +645,47 @@
         // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT.
         setNetworkVisible(false, false, false);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
 
         // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
         setNetworkVisible(false, false, true);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
 
         // Only one of Ethernet, MobileData is displayed.
         // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT.
         setNetworkVisible(true, false, false);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
 
         setNetworkVisible(false, true, false);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
 
         // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
         setNetworkVisible(true, false, true);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
 
         setNetworkVisible(false, true, true);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
 
         // Both of Ethernet, MobileData, ConnectedWiFi is displayed.
         // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT - 1.
         setNetworkVisible(true, true, false);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
 
         // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
         setNetworkVisible(true, true, true);
 
-        assertThat(mInternetDialog.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT - 2);
+        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 2);
     }
 
     @Test
@@ -676,9 +693,9 @@
         when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
                 .thenReturn(null);
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
-        assertThat(mInternetDialog.mShareWifiButton.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
@@ -686,9 +703,10 @@
         when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
                 .thenReturn(new Intent());
 
-        mInternetDialog.updateDialog(false);
+        mInternetDialogDelegate.updateDialog(false);
 
-        assertThat(mInternetDialog.mShareWifiButton.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility())
+                .isEqualTo(View.VISIBLE);
     }
 
     private void setNetworkVisible(boolean ethernetVisible, boolean mobileDataVisible,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 992658a..db455cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -96,6 +96,7 @@
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewConfigurator;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository;
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
@@ -354,6 +355,7 @@
     protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
     protected KeyguardClockInteractor mKeyguardClockInteractor;
     protected FakeKeyguardRepository mFakeKeyguardRepository;
+    protected FakeKeyguardClockRepository mFakeKeyguardClockRepository;
     protected KeyguardInteractor mKeyguardInteractor;
     protected ShadeAnimationInteractor mShadeAnimationInteractor;
     protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
@@ -399,6 +401,8 @@
                 KeyguardInteractorFactory.create();
         mFakeKeyguardRepository = keyguardInteractorDeps.getRepository();
         mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(mFakeKeyguardRepository);
+        mFakeKeyguardClockRepository = new FakeKeyguardClockRepository();
+        mKeyguardClockInteractor = new KeyguardClockInteractor(mFakeKeyguardClockRepository);
         mKeyguardInteractor = keyguardInteractorDeps.getKeyguardInteractor();
         mShadeRepository = new FakeShadeRepository();
         mShadeAnimationInteractor = new ShadeAnimationInteractorLegacyImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index ab5e51c..59fe813 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -207,7 +207,7 @@
     @Test
     fun testDragDownHelperCalledWhenDraggingDown() =
         testScope.runTest {
-            mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+            mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
             whenever(dragDownHelper.isDraggingDown).thenReturn(true)
             val now = SystemClock.elapsedRealtime()
             val ev = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 0f, 0f, 0 /* meta */)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt
index 4cc1234..81d0e06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt
@@ -27,7 +27,7 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags as AConfigFlags
-import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR
+import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.fragments.FragmentHostManager
 import com.android.systemui.fragments.FragmentService
@@ -167,7 +167,7 @@
     fun testLargeScreen_updateResources_refactorFlagOff_splitShadeHeightIsSetBasedOnResource() {
         val headerResourceHeight = 20
         val headerHelperHeight = 30
-        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight())
             .thenReturn(headerHelperHeight)
         overrideResource(R.bool.config_use_large_screen_shade_header, true)
@@ -190,7 +190,7 @@
     fun testLargeScreen_updateResources_refactorFlagOn_splitShadeHeightIsSetBasedOnHelper() {
         val headerResourceHeight = 20
         val headerHelperHeight = 30
-        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight())
             .thenReturn(headerHelperHeight)
         overrideResource(R.bool.config_use_large_screen_shade_header, true)
@@ -401,7 +401,7 @@
 
     @Test
     fun testSplitShadeLayout_isAlignedToGuideline() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
         enableSplitShade()
         underTest.updateResources()
         assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd).isEqualTo(R.id.qs_edge_guideline)
@@ -411,7 +411,7 @@
 
     @Test
     fun testSinglePaneLayout_childrenHaveEqualMargins() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
         disableSplitShade()
         underTest.updateResources()
         val qsStartMargin = getConstraintSetLayout(R.id.qs_frame).startMargin
@@ -428,7 +428,7 @@
 
     @Test
     fun testSplitShadeLayout_childrenHaveInsideMarginsOfZero() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
         enableSplitShade()
         underTest.updateResources()
         assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0)
@@ -446,8 +446,8 @@
 
     @Test
     fun testLargeScreenLayout_refactorFlagOff_qsAndNotifsTopMarginIsOfHeaderHeightResource() {
-        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         setLargeScreen()
         val largeScreenHeaderResourceHeight = 100
         val largeScreenHeaderHelperHeight = 200
@@ -469,8 +469,8 @@
 
     @Test
     fun testLargeScreenLayout_refactorFlagOn_qsAndNotifsTopMarginIsOfHeaderHeightHelper() {
-        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         setLargeScreen()
         val largeScreenHeaderResourceHeight = 100
         val largeScreenHeaderHelperHeight = 200
@@ -492,7 +492,7 @@
 
     @Test
     fun testSmallScreenLayout_qsAndNotifsTopMarginIsZero() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
         setSmallScreen()
         underTest.updateResources()
         assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin).isEqualTo(0)
@@ -513,7 +513,7 @@
 
     @Test
     fun testSinglePaneShadeLayout_isAlignedToParent() {
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL)
+        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
         disableSplitShade()
         underTest.updateResources()
         assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
index d7eada8..4ae751b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
@@ -26,7 +26,7 @@
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR
+import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.fragments.FragmentHostManager
 import com.android.systemui.fragments.FragmentService
@@ -162,7 +162,7 @@
 
     @Test
     fun testLargeScreen_updateResources_refactorFlagOff_splitShadeHeightIsSet_basedOnResource() {
-        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         val helperHeight = 30
         val resourceHeight = 20
         whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(helperHeight)
@@ -183,7 +183,7 @@
 
     @Test
     fun testLargeScreen_updateResources_refactorFlagOn_splitShadeHeightIsSet_basedOnHelper() {
-        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         val helperHeight = 30
         val resourceHeight = 20
         whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(helperHeight)
@@ -425,7 +425,7 @@
 
     @Test
     fun testLargeScreenLayout_refactorFlagOff_qsAndNotifsTopMarginIsOfHeaderResourceHeight() {
-        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+        mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         setLargeScreen()
         val largeScreenHeaderHelperHeight = 200
         val largeScreenHeaderResourceHeight = 100
@@ -445,7 +445,7 @@
 
     @Test
     fun testLargeScreenLayout_refactorFlagOn_qsAndNotifsTopMarginIsOfHeaderHelperHeight() {
-        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+        mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
         setLargeScreen()
         val largeScreenHeaderHelperHeight = 200
         val largeScreenHeaderResourceHeight = 100
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index f178046..b6ee46d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -52,8 +52,8 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.NotificationContentDescription;
 
 import org.junit.Before;
@@ -153,7 +153,7 @@
         Icon icon = Icon.createWithBitmap(bitmap);
         StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
                 icon, 0, 0, "");
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         mIconView.getIcon(largeIcon);
         // no crash? good
 
@@ -196,7 +196,7 @@
         // the icon view layout size would be 60x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, dpIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 50x50. When put the drawable into iconView whose
         // layout size is 60x150, the drawable size would not be constrained and thus keep 50x50
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
@@ -215,7 +215,7 @@
         // the icon view layout size would be 60x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, dpIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 50x100. When put the drawable into iconView whose
         // layout size is 60x150, the drawable size would not be constrained and thus keep 50x100
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 100);
@@ -235,7 +235,7 @@
         // the icon view layout size would be 60x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, dpIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 100x50. When put the drawable into iconView whose
         // layout size is 60x150, the drawable size would be constrained to 60x30
         setIconDrawableWithSize(/* width= */ 100, /* height= */ 50);
@@ -257,7 +257,7 @@
         // the icon view layout size would be 40x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 50x50. When put the drawable into iconView whose
         // layout size is 40x150, the drawable size would be constrained to 40x40
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
@@ -283,7 +283,7 @@
         // the icon view layout size would be 40x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 70x70. When put the drawable into iconView whose
         // layout size is 40x150, the drawable size would be constrained to 40x40
         setIconDrawableWithSize(/* width= */ 70, /* height= */ 70);
@@ -310,7 +310,7 @@
         // the icon view layout size would be 40x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 50x100. When put the drawable into iconView whose
         // layout size is 40x150, the drawable size would be constrained to 40x80
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 100);
@@ -334,7 +334,7 @@
         // the icon view layout size would be 80x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 50x50. When put the drawable into iconView whose
         // layout size is 80x150, the drawable size would not be constrained and thus keep 50x50
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
@@ -357,7 +357,7 @@
         // the icon view layout size would be 80x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 50x100. When put the drawable into iconView whose
         // layout size is 80x150, the drawable size would not be constrained and thus keep 50x100
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 100);
@@ -381,7 +381,7 @@
         // the icon view layout size would be 80x150
         //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
         setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
-        mIconView.setNotification(mock(StatusBarNotification.class));
+        mIconView.setNotification(getMockSbn());
         // the raw drawable size is 100x50. When put the drawable into iconView whose
         // layout size is 80x150, the drawable size would not be constrained and thus keep 80x40
         setIconDrawableWithSize(/* width= */ 100, /* height= */ 50);
@@ -397,6 +397,12 @@
                 mIconView.getIconScale(), 0.01f);
     }
 
+    private static StatusBarNotification getMockSbn() {
+        StatusBarNotification sbn = mock(StatusBarNotification.class);
+        when(sbn.getNotification()).thenReturn(mock(Notification.class));
+        return sbn;
+    }
+
     /**
      * Setup iconView dimens for testing. The result icon view layout width would
      * be spIconSize and height would be 150.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
index 590c902..b548117 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
@@ -28,12 +29,15 @@
 
 import android.app.Notification.MediaStyle;
 import android.media.session.MediaSession;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.service.notification.NotificationListenerService;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.media.controls.util.MediaFeatureFlag;
 import com.android.systemui.statusbar.notification.InflationException;
@@ -153,7 +157,8 @@
     }
 
     @Test
-    public void inflateMediaNotificationIconsMediaEnabled() throws InflationException {
+    @DisableFlags(Flags.FLAG_NOTIFICATIONS_BACKGROUND_MEDIA_ICONS)
+    public void inflateMediaNotificationIconsMediaEnabled_old() throws InflationException {
         finishSetupWithMediaFeatureFlagEnabled(true);
 
         mListener.onEntryInit(mMediaEntry);
@@ -181,7 +186,37 @@
     }
 
     @Test
-    public void inflationException() throws InflationException {
+    @EnableFlags(Flags.FLAG_NOTIFICATIONS_BACKGROUND_MEDIA_ICONS)
+    public void inflateMediaNotificationIconsMediaEnabled_new() throws InflationException {
+        finishSetupWithMediaFeatureFlagEnabled(true);
+
+        mListener.onEntryInit(mMediaEntry);
+        mListener.onEntryAdded(mMediaEntry);
+        verify(mIconManager).createIcons(eq(mMediaEntry));
+        verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
+        clearInvocations(mIconManager);
+
+        mFilter.shouldFilterOut(mMediaEntry, 0);
+        verify(mIconManager, never()).createIcons(eq(mMediaEntry));
+        verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
+
+        mListener.onEntryUpdated(mMediaEntry);
+        verify(mIconManager, never()).createIcons(eq(mMediaEntry));
+        verify(mIconManager).updateIcons(eq(mMediaEntry));
+
+        mListener.onEntryRemoved(mMediaEntry, NotificationListenerService.REASON_CANCEL);
+        mListener.onEntryCleanUp(mMediaEntry);
+        clearInvocations(mIconManager);
+
+        mListener.onEntryInit(mMediaEntry);
+        mListener.onEntryAdded(mMediaEntry);
+        verify(mIconManager).createIcons(eq(mMediaEntry));
+        verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_NOTIFICATIONS_BACKGROUND_MEDIA_ICONS)
+    public void inflationException_old() throws InflationException {
         finishSetupWithMediaFeatureFlagEnabled(true);
 
         mListener.onEntryInit(mMediaEntry);
@@ -208,6 +243,31 @@
         verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_NOTIFICATIONS_BACKGROUND_MEDIA_ICONS)
+    public void inflationException_new() throws InflationException {
+        finishSetupWithMediaFeatureFlagEnabled(true);
+
+        doThrow(InflationException.class).when(mIconManager).createIcons(eq(mMediaEntry));
+
+        mListener.onEntryInit(mMediaEntry);
+        mListener.onEntryAdded(mMediaEntry);
+        verify(mIconManager).createIcons(eq(mMediaEntry));
+        verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
+        clearInvocations(mIconManager);
+
+        mListener.onEntryUpdated(mMediaEntry);
+        verify(mIconManager).createIcons(eq(mMediaEntry));
+        verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
+        clearInvocations(mIconManager);
+
+        doNothing().when(mIconManager).createIcons(eq(mMediaEntry));
+
+        mListener.onEntryUpdated(mMediaEntry);
+        verify(mIconManager).createIcons(eq(mMediaEntry));
+        verify(mIconManager, never()).updateIcons(eq(mMediaEntry));
+    }
+
     private void finishSetupWithMediaFeatureFlagEnabled(boolean mediaFeatureFlagEnabled) {
         when(mMediaFeatureFlag.getEnabled()).thenReturn(mediaFeatureFlagEnabled);
         mCoordinator = new MediaCoordinator(mMediaFeatureFlag, mStatusBarService, mIconManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
index 0830191..b1d2ea21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
+import com.android.systemui.statusbar.notification.ColorUpdateLogger
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -57,6 +58,7 @@
     private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
     private val gutsManager: NotificationGutsManager = mock()
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock()
+    private val colorUpdateLogger: ColorUpdateLogger = mock()
 
     @Before
     fun setUp() {
@@ -66,7 +68,9 @@
             configurationController,
             lockscreenUserManager,
             gutsManager,
-            keyguardUpdateMonitor)
+            keyguardUpdateMonitor,
+            colorUpdateLogger,
+        )
         coordinator.attach(pipeline)
         userChangedListener = withArgCaptor {
             verify(lockscreenUserManager).addUserChangedListener(capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 8ac2a33..210b1a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.SbnBuilder
 import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.ColorUpdateLogger
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
@@ -82,6 +83,7 @@
     private val rivSubComponentFactory: RemoteInputViewSubcomponent.Factory = mock()
     private val metricsLogger: MetricsLogger = mock()
     private val logBufferLogger = NotificationRowLogger(logcatLogBuffer(), logcatLogBuffer())
+    private val colorUpdateLogger: ColorUpdateLogger = mock()
     private val listContainer: NotificationListContainer = mock()
     private val childrenContainer: NotificationChildrenContainer = mock()
     private val smartReplyConstants: SmartReplyConstants = mock()
@@ -117,6 +119,7 @@
                 activableNotificationViewController,
                 rivSubComponentFactory,
                 metricsLogger,
+                colorUpdateLogger,
                 logBufferLogger,
                 NotificationChildrenContainerLogger(logcatLogBuffer()),
                 listContainer,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index c717991..e78081f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -65,6 +65,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -607,6 +608,7 @@
                 mDismissibilityProvider,
                 mock(MetricsLogger.class),
                 new NotificationChildrenContainerLogger(logcatLogBuffer()),
+                mock(ColorUpdateLogger.class),
                 mock(SmartReplyConstants.class),
                 mock(SmartReplyController.class),
                 mFeatureFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 354f3f6..f2ef4e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -78,6 +78,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -148,6 +149,7 @@
     @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private MetricsLogger mMetricsLogger;
+    @Mock private ColorUpdateLogger mColorUpdateLogger;
     @Mock private DumpManager mDumpManager;
     @Mock(answer = Answers.RETURNS_SELF)
     private NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
@@ -1007,6 +1009,7 @@
                 mZenModeController,
                 mNotificationLockscreenUserManager,
                 mMetricsLogger,
+                mColorUpdateLogger,
                 mDumpManager,
                 new FalsingCollectorFake(),
                 new FalsingManagerFake(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 2da88e9..b9b8722 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -21,7 +21,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR
+import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
@@ -134,7 +134,7 @@
     @Test
     fun validatePaddingTopInSplitShade_refactorFlagOff_usesLargeHeaderResource() =
         testScope.runTest {
-            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
             whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
                 .thenReturn(true)
@@ -153,7 +153,7 @@
     @Test
     fun validatePaddingTopInSplitShade_refactorFlagOn_usesLargeHeaderHelper() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
             whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
                 .thenReturn(true)
@@ -210,7 +210,7 @@
     @Test
     fun validateMarginTopWithLargeScreenHeader_refactorFlagOff_usesResource() =
         testScope.runTest {
-            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val headerResourceHeight = 50
             val headerHelperHeight = 100
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight())
@@ -229,7 +229,7 @@
     @Test
     fun validateMarginTopWithLargeScreenHeader_refactorFlagOn_usesHelper() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val headerResourceHeight = 50
             val headerHelperHeight = 100
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight())
@@ -449,7 +449,7 @@
     @Test
     fun boundsOnLockscreenInSplitShade_refactorFlagOff_usesLargeHeaderResource() =
         testScope.runTest {
-            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val bounds by collectLastValue(underTest.bounds)
 
             // When in split shade
@@ -478,7 +478,7 @@
     @Test
     fun boundsOnLockscreenInSplitShade_refactorFlagOn_usesLargeHeaderHelper() =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR)
+            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             val bounds by collectLastValue(underTest.bounds)
 
             // When in split shade
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 38698f8..fd295b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -298,7 +298,7 @@
 
     @Test
     public void notifPaddingMakesUpToFullMarginInSplitShade_refactorFlagOff_usesResource() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR);
+        mSetFlagsRule.disableFlags(Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX);
         int keyguardSplitShadeTopMargin = 100;
         int largeScreenHeaderHeightResource = 70;
         when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
@@ -317,7 +317,7 @@
 
     @Test
     public void notifPaddingMakesUpToFullMarginInSplitShade_refactorFlagOn_usesHelper() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_CENTRALIZED_STATUS_BAR_DIMENS_REFACTOR);
+        mSetFlagsRule.enableFlags(Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX);
         int keyguardSplitShadeTopMargin = 100;
         int largeScreenHeaderHeightHelper = 50;
         int largeScreenHeaderHeightResource = 70;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 41b959e..9d53b9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -119,7 +119,7 @@
 
     @Test
     public void testAppearResetsTranslation() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL);
+        mSetFlagsRule.disableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT);
         mController.setupAodIcons(mAodIcons);
         when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
         mController.appearAodIcons();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index f1a2c28..ddd29c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -79,6 +79,7 @@
         mController = new ZenModeControllerImpl(
                 mContext,
                 Handler.createAsync(TestableLooper.get(this).getLooper()),
+                Handler.createAsync(TestableLooper.get(this).getLooper()),
                 mBroadcastDispatcher,
                 mDumpManager,
                 mGlobalSettings,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FakeCredentialInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FakeCredentialInteractor.kt
index fbe291e..a4c8a0b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FakeCredentialInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FakeCredentialInteractor.kt
@@ -14,10 +14,15 @@
     /** Sets return value for [getCredentialOwnerOrSelfId]. */
     var credentialOwnerId: Int? = null
 
+    /** Sets return value for [getParentProfileIdOrSelfId]. */
+    var userIdForPasswordEntry: Int? = null
+
     override fun isStealthModeActive(userId: Int): Boolean = stealthMode
 
     override fun getCredentialOwnerOrSelfId(userId: Int): Int = credentialOwnerId ?: userId
 
+    override fun getParentProfileIdOrSelfId(userId: Int): Int = userIdForPasswordEntry ?: userId
+
     override fun verifyCredential(
         request: BiometricPromptRequest.Credential,
         credential: LockscreenCredential,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index f7e9a11..566fc25 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -21,12 +21,16 @@
 import com.android.systemui.communal.data.repository.communalRepository
 import com.android.systemui.communal.data.repository.communalWidgetRepository
 import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.smartspace.data.repository.smartspaceRepository
+import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.mock
 
 val Kosmos.communalInteractor by Fixture {
@@ -47,3 +51,14 @@
 }
 
 val Kosmos.editWidgetsActivityStarter by Fixture<EditWidgetsActivityStarter> { mock() }
+
+suspend fun Kosmos.setCommunalAvailable(available: Boolean) {
+    fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, available)
+    if (available) {
+        fakeUserRepository.asMainUser()
+        with(fakeKeyguardRepository) {
+            setIsEncryptedOrLockdown(false)
+            setKeyguardShowing(true)
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
index c51de33..46a1053 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -43,6 +43,7 @@
     }
 
     override fun isLayoutRtl(): Boolean = isRtl
+    override fun getNightModeName(): String = "undefined"
 }
 
 @Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index 1124425..931a59d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -39,13 +39,19 @@
         // User id to represent a non system (human) user id. We presume this is the main user.
         private const val MAIN_USER_ID = 10
 
-        private val DEFAULT_SELECTED_USER = 0
+        private const val DEFAULT_SELECTED_USER = 0
         private val DEFAULT_SELECTED_USER_INFO =
             UserInfo(
                 /* id= */ DEFAULT_SELECTED_USER,
                 /* name= */ "default selected user",
                 /* flags= */ 0,
             )
+        private val MAIN_USER =
+            UserInfo(
+                /* id= */ MAIN_USER_ID,
+                /* name= */ "main user",
+                /* flags= */ UserInfo.FLAG_MAIN,
+            )
     }
 
     private val _userSwitcherSettings = MutableStateFlow(UserSwitcherSettingsModel())
@@ -113,6 +119,13 @@
         yield()
     }
 
+    /** Makes the current user [MAIN_USER]. */
+    suspend fun asMainUser(): UserInfo {
+        setUserInfos(listOf(MAIN_USER))
+        setSelectedUserInfo(MAIN_USER)
+        return MAIN_USER
+    }
+
     suspend fun setSettings(settings: UserSwitcherSettingsModel) {
         _userSwitcherSettings.value = settings
         yield()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index 516eb6e..111c40d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -38,4 +38,9 @@
     public boolean isLayoutRtl() {
         return false;
     }
+
+    @Override
+    public String getNightModeName() {
+        return "undefined";
+    }
 }
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index 053ed77..3ecdf3f 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -36,9 +36,11 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -57,6 +59,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
@@ -78,6 +81,7 @@
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -87,6 +91,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 @RunWith(AndroidJUnit4.class)
@@ -815,6 +820,48 @@
                 WallpaperEventLogger.ERROR_LIVE_PACKAGE_NOT_INSTALLED);
     }
 
+    @Test
+    public void testOnRestore_noCropHints() throws Exception {
+        testParseCropHints(Map.of());
+    }
+
+    @Test
+    public void testOnRestore_singleCropHint() throws Exception {
+        Map<Integer, Rect> testMap = Map.of(WallpaperManager.PORTRAIT, new Rect(1, 2, 3, 4));
+        testParseCropHints(testMap);
+    }
+
+    @Test
+    public void testOnRestore_multipleCropHints() throws Exception {
+        Map<Integer, Rect> testMap = Map.of(
+                WallpaperManager.PORTRAIT, new Rect(1, 2, 3, 4),
+                WallpaperManager.SQUARE_PORTRAIT, new Rect(5, 6, 7, 8),
+                WallpaperManager.SQUARE_LANDSCAPE, new Rect(9, 10, 11, 12));
+        testParseCropHints(testMap);
+    }
+
+    private void testParseCropHints(Map<Integer, Rect> testMap) throws Exception {
+        assumeTrue(multiCrop());
+        mockRestoredStaticWallpaperFile(testMap);
+        mockStagedWallpaperFile(SYSTEM_WALLPAPER_STAGE);
+        mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
+                BackupAnnotations.OperationType.RESTORE);
+
+        mWallpaperBackupAgent.onRestoreFinished();
+
+        ArgumentMatcher<SparseArray<Rect>> matcher = array -> {
+            boolean result = testMap.entrySet().stream().allMatch(entry -> {
+                int key = entry.getKey();
+                return (array.contains(key) && array.get(key).equals(testMap.get(key)));
+            });
+            for (int i = 0; i < array.size(); i++) {
+                if (!testMap.containsKey(array.keyAt(i))) result = false;
+            }
+            return result;
+        };
+        verify(mWallpaperManager).setStreamWithCrops(any(), argThat(matcher), eq(true), anyInt());
+    }
+
     private void mockCurrentWallpaperIds(int systemWallpaperId, int lockWallpaperId) {
         when(mWallpaperManager.getWallpaperId(eq(FLAG_SYSTEM))).thenReturn(systemWallpaperId);
         when(mWallpaperManager.getWallpaperId(eq(FLAG_LOCK))).thenReturn(lockWallpaperId);
@@ -880,6 +927,34 @@
         fstream.close();
     }
 
+    private void mockRestoredStaticWallpaperFile(Map<Integer, Rect> crops) throws Exception {
+        File wallpaperFile = new File(mContext.getFilesDir(), WALLPAPER_INFO_STAGE);
+        wallpaperFile.createNewFile();
+        FileOutputStream fstream = new FileOutputStream(wallpaperFile, false);
+        TypedXmlSerializer out = Xml.resolveSerializer(fstream);
+        out.startDocument(null, true);
+        out.startTag(null, "wp");
+        for (Map.Entry<Integer, Rect> entry: crops.entrySet()) {
+            String orientation = switch (entry.getKey()) {
+                case WallpaperManager.PORTRAIT -> "Portrait";
+                case WallpaperManager.LANDSCAPE -> "Landscape";
+                case WallpaperManager.SQUARE_PORTRAIT -> "SquarePortrait";
+                case WallpaperManager.SQUARE_LANDSCAPE -> "SquareLandscape";
+                default -> throw new IllegalArgumentException("Invalid orientation");
+            };
+            Rect rect = entry.getValue();
+            out.attributeInt(null, "cropLeft" + orientation, rect.left);
+            out.attributeInt(null, "cropTop" + orientation, rect.top);
+            out.attributeInt(null, "cropRight" + orientation, rect.right);
+            out.attributeInt(null, "cropBottom" + orientation, rect.bottom);
+        }
+        out.endTag(null, "wp");
+        out.endDocument();
+        fstream.flush();
+        FileUtils.sync(fstream);
+        fstream.close();
+    }
+
     private WallpaperInfo getFakeWallpaperInfo() throws Exception {
         Context context = InstrumentationRegistry.getTargetContext();
         Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
diff --git a/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java b/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java
index 1f18e15..9b27dd3 100644
--- a/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java
@@ -42,7 +42,6 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -112,7 +111,7 @@
     BrailleDisplayConnection(@NonNull Object lock,
             @NonNull AccessibilityServiceConnection serviceConnection) {
         this.mLock = Objects.requireNonNull(lock);
-        this.mScanner = getDefaultNativeScanner(getDefaultNativeInterface());
+        this.mScanner = getDefaultNativeScanner(new DefaultNativeInterface());
         this.mServiceConnection = Objects.requireNonNull(serviceConnection);
     }
 
@@ -128,7 +127,7 @@
      */
     @VisibleForTesting
     interface BrailleDisplayScanner {
-        Collection<Path> getHidrawNodePaths();
+        Collection<Path> getHidrawNodePaths(@NonNull Path directory);
 
         byte[] getDeviceReportDescriptor(@NonNull Path path);
 
@@ -158,8 +157,9 @@
         Objects.requireNonNull(expectedUniqueId);
         this.mController = Objects.requireNonNull(controller);
 
+        final Path devicePath = Path.of("/dev");
         final List<Pair<File, byte[]>> result = new ArrayList<>();
-        final Collection<Path> hidrawNodePaths = mScanner.getHidrawNodePaths();
+        final Collection<Path> hidrawNodePaths = mScanner.getHidrawNodePaths(devicePath);
         if (hidrawNodePaths == null) {
             Slog.w(LOG_TAG, "Unable to access the HIDRAW node directory");
             sendConnectionErrorLocked(FLAG_ERROR_CANNOT_ACCESS);
@@ -285,6 +285,9 @@
         if (buffer.length > IBinder.getSuggestedMaxIpcSizeBytes()) {
             Slog.e(LOG_TAG, "Requested write of size " + buffer.length
                     + " which is larger than maximum " + IBinder.getSuggestedMaxIpcSizeBytes());
+            // The caller only got here by bypassing the AccessibilityService-side check with
+            // reflection, so disconnect this connection to prevent further attempts.
+            disconnect();
             return;
         }
         synchronized (mLock) {
@@ -292,7 +295,7 @@
             if (mOutputThread == null) {
                 try {
                     mOutputStream = new FileOutputStream(mHidrawNode);
-                } catch (FileNotFoundException e) {
+                } catch (Exception e) {
                     Slog.e(LOG_TAG, "Unable to create write stream", e);
                     disconnect();
                     return;
@@ -387,14 +390,13 @@
     BrailleDisplayScanner getDefaultNativeScanner(@NonNull NativeInterface nativeInterface) {
         Objects.requireNonNull(nativeInterface);
         return new BrailleDisplayScanner() {
-            private static final Path DEVICE_DIR = Path.of("/dev");
             private static final String HIDRAW_DEVICE_GLOB = "hidraw*";
 
             @Override
-            public Collection<Path> getHidrawNodePaths() {
+            public Collection<Path> getHidrawNodePaths(@NonNull Path directory) {
                 final List<Path> result = new ArrayList<>();
                 try (DirectoryStream<Path> hidrawNodePaths = Files.newDirectoryStream(
-                        DEVICE_DIR, HIDRAW_DEVICE_GLOB)) {
+                        directory, HIDRAW_DEVICE_GLOB)) {
                     for (Path path : hidrawNodePaths) {
                         result.add(path);
                     }
@@ -458,8 +460,8 @@
         synchronized (mLock) {
             mScanner = new BrailleDisplayScanner() {
                 @Override
-                public Collection<Path> getHidrawNodePaths() {
-                    return brailleDisplayMap.keySet();
+                public Collection<Path> getHidrawNodePaths(@NonNull Path directory) {
+                    return brailleDisplayMap.isEmpty() ? null : brailleDisplayMap.keySet();
                 }
 
                 @Override
@@ -490,38 +492,56 @@
      */
     @VisibleForTesting
     interface NativeInterface {
+        /**
+         * Returns the HIDRAW descriptor size for the file descriptor.
+         *
+         * @return the result of ioctl(HIDIOCGRDESCSIZE), or -1 if the ioctl fails.
+         */
         int getHidrawDescSize(int fd);
 
+        /**
+         * Returns the HIDRAW descriptor for the file descriptor.
+         *
+         * @return the result of ioctl(HIDIOCGRDESC), or null if the ioctl fails.
+         */
         byte[] getHidrawDesc(int fd, int descSize);
 
+        /**
+         * Returns the HIDRAW unique identifier for the file descriptor.
+         *
+         * @return the result of ioctl(HIDIOCGRAWUNIQ), or null if the ioctl fails.
+         */
         String getHidrawUniq(int fd);
 
+        /**
+         * Returns the HIDRAW bus type for the file descriptor.
+         *
+         * @return the result of ioctl(HIDIOCGRAWINFO).bustype, or -1 if the ioctl fails.
+         */
         int getHidrawBusType(int fd);
     }
 
     /** Native interface that actually calls native HIDRAW ioctls. */
-    private NativeInterface getDefaultNativeInterface() {
-        return new NativeInterface() {
-            @Override
-            public int getHidrawDescSize(int fd) {
-                return nativeGetHidrawDescSize(fd);
-            }
+    private class DefaultNativeInterface implements NativeInterface {
+        @Override
+        public int getHidrawDescSize(int fd) {
+            return nativeGetHidrawDescSize(fd);
+        }
 
-            @Override
-            public byte[] getHidrawDesc(int fd, int descSize) {
-                return nativeGetHidrawDesc(fd, descSize);
-            }
+        @Override
+        public byte[] getHidrawDesc(int fd, int descSize) {
+            return nativeGetHidrawDesc(fd, descSize);
+        }
 
-            @Override
-            public String getHidrawUniq(int fd) {
-                return nativeGetHidrawUniq(fd);
-            }
+        @Override
+        public String getHidrawUniq(int fd) {
+            return nativeGetHidrawUniq(fd);
+        }
 
-            @Override
-            public int getHidrawBusType(int fd) {
-                return nativeGetHidrawBusType(fd);
-            }
-        };
+        @Override
+        public int getHidrawBusType(int fd) {
+            return nativeGetHidrawBusType(fd);
+        }
     }
 
     private native int nativeGetHidrawDescSize(int fd);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 18e11ba..eb661ce 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2413,6 +2413,16 @@
         }
 
         AppWidgetProviderInfo info = createPartialProviderInfo(providerId, ri, existing);
+
+        if (android.os.Flags.allowPrivateProfile()
+                && android.multiuser.Flags.disablePrivateSpaceItemsOnHome()) {
+            // Do not add widget providers for profiles with items restricted on home screen.
+            if (mUserManager
+                    .getUserProperties(info.getProfile()).areItemsRestrictedOnHomeScreen()) {
+                return false;
+            }
+        }
+
         if (info != null) {
             if (existing != null) {
                 if (existing.zombie && !mSafeMode) {
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index eb23f2f..3965869 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_autofill",
     // 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"
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index d47245e..5a34217 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2770,6 +2770,10 @@
                     + id + " destroyed");
             return;
         }
+        if (sDebug) {
+            Slog.d(TAG, "setAuthenticationResultLocked(): id= " + authenticationId
+                    + ", data=" + data);
+        }
         final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
         if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) {
             setAuthenticationResultForAugmentedAutofillLocked(data, authenticationId);
@@ -2823,12 +2827,18 @@
                     + ", clientState=" + newClientState + ", authenticationId=" + authenticationId);
         }
         if (result instanceof FillResponse) {
+            if (sDebug) {
+                Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from"
+                        + " authentication flow");
+            }
             logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                 AUTHENTICATION_RESULT_SUCCESS);
             replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState);
         } else if (result instanceof GetCredentialResponse) {
-            Slog.d(TAG, "Received GetCredentialResponse from authentication flow");
+            if (sDebug) {
+                Slog.d(TAG, "Received GetCredentialResponse from authentication flow");
+            }
             boolean isCredmanCallbackInvoked = false;
             if (Flags.autofillCredmanIntegration()) {
                 GetCredentialResponse response = (GetCredentialResponse) result;
@@ -2843,6 +2853,10 @@
                 }
             }
         } else if (result instanceof Dataset) {
+            if (sDebug) {
+                Slog.d(TAG, "setAuthenticationResultLocked(): received Dataset from"
+                        + " authentication flow");
+            }
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
                 logAuthenticationStatusLocked(requestId,
                         MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
diff --git a/services/companion/java/com/android/server/companion/virtual/Android.bp b/services/companion/java/com/android/server/companion/virtual/Android.bp
index 6526c78..4a2030f 100644
--- a/services/companion/java/com/android/server/companion/virtual/Android.bp
+++ b/services/companion/java/com/android/server/companion/virtual/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_team: "trendy_team_xr_framework",
+}
+
 java_aconfig_library {
     name: "virtualdevice_flags_lib",
     aconfig_declarations: "virtualdevice_flags",
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 31766f2..ff07619 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -29,6 +29,7 @@
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
+import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -44,6 +45,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.BlockedAppStreamingActivity;
+import com.android.modules.expresslog.Counter;
 
 import java.util.Set;
 
@@ -104,6 +106,8 @@
     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
     public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
     @NonNull
+    private final AttributionSource mAttributionSource;
+    @NonNull
     private final ArraySet<UserHandle> mAllowedUsers;
     @GuardedBy("mGenericWindowPolicyControllerLock")
     private boolean mActivityLaunchAllowedByDefault;
@@ -144,6 +148,7 @@
      *
      * @param windowFlags The window flags that this controller is interested in.
      * @param systemWindowFlags The system window flags that this controller is interested in.
+     * @param attributionSource The AttributionSource of the VirtualDevice owner application.
      * @param allowedUsers The set of users that are allowed to stream in this display.
      * @param activityLaunchAllowedByDefault Whether activities are default allowed to be launched
      *   or blocked.
@@ -169,6 +174,7 @@
     public GenericWindowPolicyController(
             int windowFlags,
             int systemWindowFlags,
+            AttributionSource attributionSource,
             @NonNull ArraySet<UserHandle> allowedUsers,
             boolean activityLaunchAllowedByDefault,
             @NonNull Set<ComponentName> activityPolicyExemptions,
@@ -184,6 +190,7 @@
             boolean showTasksInHostDeviceRecents,
             @Nullable ComponentName customHomeComponent) {
         super();
+        mAttributionSource = attributionSource;
         mAllowedUsers = allowedUsers;
         mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
         mActivityPolicyExemptions = activityPolicyExemptions;
@@ -436,6 +443,12 @@
         if (!mIsMirrorDisplay && mActivityBlockedCallback != null) {
             mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
         }
+        if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+            Counter.logIncrementWithUid(
+                    "virtual_devices.value_activity_blocked_count",
+                    mAttributionSource.getUid());
+        }
+
     }
 
     private static boolean isAllowedByPolicy(boolean allowedByDefault,
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index 1b49f18e..9b72288 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.StringDef;
+import android.content.AttributionSource;
 import android.graphics.PointF;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputDeviceIdentifier;
@@ -38,6 +39,7 @@
 import android.os.IInputConstants;
 import android.os.RemoteException;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 import android.view.InputDevice;
@@ -45,6 +47,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.expresslog.Counter;
 import com.android.server.LocalServices;
 import com.android.server.input.InputManagerInternal;
 
@@ -98,11 +101,12 @@
     private final DisplayManagerInternal mDisplayManagerInternal;
     private final InputManagerInternal mInputManagerInternal;
     private final WindowManager mWindowManager;
+    private final AttributionSource mAttributionSource;
     private final DeviceCreationThreadVerifier mThreadVerifier;
 
     InputController(@NonNull Handler handler,
-            @NonNull WindowManager windowManager) {
-        this(new NativeWrapper(), handler, windowManager,
+            @NonNull WindowManager windowManager, AttributionSource attributionSource) {
+        this(new NativeWrapper(), handler, windowManager, attributionSource,
                 // Verify that virtual devices are not created on the handler thread.
                 () -> !handler.getLooper().isCurrentThread());
     }
@@ -110,12 +114,14 @@
     @VisibleForTesting
     InputController(@NonNull NativeWrapper nativeWrapper,
             @NonNull Handler handler, @NonNull WindowManager windowManager,
+            AttributionSource attributionSource,
             @NonNull DeviceCreationThreadVerifier threadVerifier) {
         mHandler = handler;
         mNativeWrapper = nativeWrapper;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mWindowManager = windowManager;
+        mAttributionSource = attributionSource;
         mThreadVerifier = threadVerifier;
     }
 
@@ -838,6 +844,33 @@
                     new InputDeviceDescriptor(ptr, binderDeathRecipient, type, displayId, phys,
                             deviceName, inputDeviceId));
         }
+
+        if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+            String metricId = getMetricIdForInputType(type);
+            if (metricId != null) {
+                Counter.logIncrementWithUid(metricId, mAttributionSource.getUid());
+            }
+        }
+    }
+
+    private static String getMetricIdForInputType(@InputDeviceDescriptor.Type int type) {
+        switch (type) {
+            case InputDeviceDescriptor.TYPE_KEYBOARD:
+                return "virtual_devices.value_virtual_keyboard_created_count";
+            case InputDeviceDescriptor.TYPE_MOUSE:
+                return "virtual_devices.value_virtual_mouse_created_count";
+            case InputDeviceDescriptor.TYPE_TOUCHSCREEN:
+                return "virtual_devices.value_virtual_touchscreen_created_count";
+            case InputDeviceDescriptor.TYPE_DPAD:
+                return "virtual_devices.value_virtual_dpad_created_count";
+            case InputDeviceDescriptor.TYPE_NAVIGATION_TOUCHPAD:
+                return "virtual_devices.value_virtual_navigationtouchpad_created_count";
+            case InputDeviceDescriptor.TYPE_STYLUS:
+                return "virtual_devices.value_virtual_stylus_created_count";
+            default:
+                Log.e(TAG, "No metric known for input type: " + type);
+                return null;
+        }
     }
 
     @VisibleForTesting
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index e9241dd..cf48180 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -23,6 +23,7 @@
 import android.companion.virtual.sensor.VirtualSensor;
 import android.companion.virtual.sensor.VirtualSensorConfig;
 import android.companion.virtual.sensor.VirtualSensorEvent;
+import android.content.AttributionSource;
 import android.hardware.SensorDirectChannel;
 import android.os.Binder;
 import android.os.IBinder;
@@ -35,6 +36,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.expresslog.Counter;
 import com.android.server.LocalServices;
 import com.android.server.sensors.SensorManagerInternal;
 
@@ -71,14 +73,18 @@
     private List<VirtualSensor> mVirtualSensorList = null;
 
     @NonNull
+    private final AttributionSource mAttributionSource;
+    @NonNull
     private final SensorManagerInternal.RuntimeSensorCallback mRuntimeSensorCallback;
     private final SensorManagerInternal mSensorManagerInternal;
     private final VirtualDeviceManagerInternal mVdmInternal;
 
     public SensorController(@NonNull IVirtualDevice virtualDevice, int virtualDeviceId,
+            @NonNull AttributionSource attributionSource,
             @Nullable IVirtualSensorCallback virtualSensorCallback,
             @NonNull List<VirtualSensorConfig> sensors) {
         mVirtualDeviceId = virtualDeviceId;
+        mAttributionSource = attributionSource;
         mRuntimeSensorCallback = new RuntimeSensorCallbackWrapper(virtualSensorCallback);
         mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
         mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
@@ -139,6 +145,11 @@
             mSensorDescriptors.put(sensorToken, sensorDescriptor);
             mVirtualSensors.put(handle, sensor);
         }
+        if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+            Counter.logIncrementWithUid(
+                    "virtual_devices.value_virtual_sensors_created_count",
+                    mAttributionSource.getUid());
+        }
     }
 
     boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index f13f49a..6d731b2 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -104,6 +104,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.BlockedAppStreamingActivity;
+import com.android.modules.expresslog.Counter;
 import com.android.server.LocalServices;
 import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
 import com.android.server.companion.virtual.audio.VirtualAudioController;
@@ -152,6 +153,8 @@
     private final int mOwnerUid;
     private final VirtualDeviceLog mVirtualDeviceLog;
     private final String mOwnerPackageName;
+    @NonNull
+    private final AttributionSource mAttributionSource;
     private final int mDeviceId;
     @Nullable
     private final String mPersistentDeviceId;
@@ -288,6 +291,7 @@
         super(PermissionEnforcer.fromContext(context));
         mVirtualDeviceLog = virtualDeviceLog;
         mOwnerPackageName = attributionSource.getPackageName();
+        mAttributionSource = attributionSource;
         UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(attributionSource.getUid());
         mContext = context.createContextAsUser(ownerUserHandle, 0);
         mAssociationInfo = associationInfo;
@@ -307,11 +311,11 @@
         if (inputController == null) {
             mInputController = new InputController(
                     context.getMainThreadHandler(),
-                    context.getSystemService(WindowManager.class));
+                    context.getSystemService(WindowManager.class), mAttributionSource);
         } else {
             mInputController = inputController;
         }
-        mSensorController = new SensorController(this, mDeviceId,
+        mSensorController = new SensorController(this, mDeviceId, mAttributionSource,
                 mParams.getVirtualSensorCallback(), mParams.getVirtualSensorConfigs());
         mCameraAccessController = cameraAccessController;
         if (mCameraAccessController != null) {
@@ -620,7 +624,7 @@
             }
 
             if (mVirtualAudioController == null) {
-                mVirtualAudioController = new VirtualAudioController(mContext);
+                mVirtualAudioController = new VirtualAudioController(mContext, mAttributionSource);
                 GenericWindowPolicyController gwpc = mVirtualDisplays.get(
                         displayId).getWindowPolicyController();
                 mVirtualAudioController.startListening(gwpc, routingCallback,
@@ -1028,7 +1032,7 @@
         if (mVirtualCameraController == null) {
             throw new UnsupportedOperationException("Virtual camera controller is not available");
         }
-        mVirtualCameraController.registerCamera(cameraConfig);
+        mVirtualCameraController.registerCamera(cameraConfig, mAttributionSource);
     }
 
     @Override // Binder call
@@ -1110,6 +1114,7 @@
         final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
                 FLAG_SECURE,
                 SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+                mAttributionSource,
                 getAllowedUserHandles(),
                 activityLaunchAllowedByDefault,
                 mActivityPolicyExemptions,
@@ -1179,6 +1184,11 @@
             Binder.restoreCallingIdentity(token);
         }
 
+        if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+            Counter.logIncrementWithUid(
+                    "virtual_devices.value_virtual_display_created_count",
+                    mAttributionSource.getUid());
+        }
         return displayId;
     }
 
@@ -1220,6 +1230,12 @@
         if ((display.getFlags() & FLAG_SECURE) == 0) {
             showToastWhereUidIsRunning(uid, com.android.internal.R.string.vdm_secure_window,
                     Toast.LENGTH_LONG, mContext.getMainLooper());
+
+            if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+                Counter.logIncrementWithUid(
+                        "virtual_devices.value_secure_window_blocked_count",
+                        mAttributionSource.getUid());
+            }
         }
     }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 2168cb2..9ad73ca 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -482,6 +482,11 @@
                     }
                 });
             }
+            if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+                Counter.logIncrementWithUid(
+                        "virtual_devices.value_virtual_devices_created_with_uid_count",
+                        attributionSource.getUid());
+            }
             return virtualDevice;
         }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
index c91877a..4bffb76 100644
--- a/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
+++ b/services/companion/java/com/android/server/companion/virtual/audio/VirtualAudioController.java
@@ -23,6 +23,7 @@
 import android.annotation.RequiresPermission;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.content.AttributionSource;
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.AudioPlaybackConfiguration;
@@ -35,6 +36,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.expresslog.Counter;
 import com.android.server.companion.virtual.GenericWindowPolicyController;
 import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
 import com.android.server.companion.virtual.audio.AudioPlaybackDetector.AudioPlaybackCallback;
@@ -70,10 +72,16 @@
     @GuardedBy("mCallbackLock")
     private IAudioConfigChangedCallback mConfigChangedCallback;
 
-    public VirtualAudioController(Context context) {
+    public VirtualAudioController(Context context, AttributionSource attributionSource) {
         mContext = context;
         mAudioPlaybackDetector = new AudioPlaybackDetector(context);
         mAudioRecordingDetector = new AudioRecordingDetector(context);
+
+        if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+            Counter.logIncrementWithUid(
+                    "virtual_devices.value_virtual_audio_created_count",
+                    attributionSource.getUid());
+        }
     }
 
     /**
diff --git a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java
index 2d82b5e..3bb1e33 100644
--- a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java
+++ b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraController.java
@@ -26,6 +26,7 @@
 import android.companion.virtual.camera.VirtualCameraConfig;
 import android.companion.virtualcamera.IVirtualCameraService;
 import android.companion.virtualcamera.VirtualCameraConfiguration;
+import android.content.AttributionSource;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -35,6 +36,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.expresslog.Counter;
 
 import java.io.PrintWriter;
 import java.util.Map;
@@ -76,7 +78,8 @@
      *
      * @param cameraConfig The {@link VirtualCameraConfig} sent by the client.
      */
-    public void registerCamera(@NonNull VirtualCameraConfig cameraConfig) {
+    public void registerCamera(@NonNull VirtualCameraConfig cameraConfig,
+            AttributionSource attributionSource) {
         checkConfigByPolicy(cameraConfig);
 
         connectVirtualCameraServiceIfNeeded();
@@ -97,6 +100,11 @@
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
+        if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
+            Counter.logIncrementWithUid(
+                    "virtual_devices.value_virtual_camera_created_count",
+                    attributionSource.getUid());
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 05010f88..f1776f4 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -17,7 +17,7 @@
 package com.android.server;
 
 import static android.app.Flags.modesApi;
-import static android.app.Flags.enableNightModeCache;
+import static android.app.Flags.enableNightModeBinderCache;
 import static android.app.UiModeManager.ContrastUtils.CONTRAST_DEFAULT_VALUE;
 import static android.app.UiModeManager.DEFAULT_PRIORITY;
 import static android.app.UiModeManager.MODE_ATTENTION_THEME_OVERLAY_OFF;
@@ -148,7 +148,7 @@
         @Override
         public void set(int mode) {
             mNightModeValue = mode;
-            if (enableNightModeCache()) {
+            if (enableNightModeBinderCache()) {
                 UiModeManager.invalidateNightModeCache();
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bfdcb95..bbd3ad0b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -930,7 +930,7 @@
      * Tracks all users with computed color resources by ThemeOverlaycvontroller
      */
     @GuardedBy("this")
-    private final Set<Integer> mThemeOverlayReadiness = new HashSet<>();
+    private final Set<Integer> mThemeOverlayReadyUsers = new HashSet<>();
 
     /**
      * Tracks association information for a particular package along with debuggability.
@@ -2351,7 +2351,7 @@
                 mService.startBroadcastObservers();
             } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
                 mService.mPackageWatchdog.onPackagesReady();
-                mService.setHomeTimeout();
+                mService.scheduleHomeTimeout();
             }
         }
 
@@ -5327,40 +5327,43 @@
     /**
      * Starts Home if there is no completion signal from ThemeOverlayController
      */
-    private void setHomeTimeout() {
+    private void scheduleHomeTimeout() {
         if (enableHomeDelay() && mHasHomeDelay.compareAndSet(false, true)) {
+            int userId = mUserController.getCurrentUserId();
             mHandler.postDelayed(() -> {
-                if (!getThemeOverlayReadiness()) {
+                if (!isThemeOverlayReady(userId)) {
                     Slog.d(TAG,
                             "ThemeHomeDelay: ThemeOverlayController not responding, launching "
                                     + "Home after "
                                     + HOME_LAUNCH_TIMEOUT_MS + "ms");
-                    setThemeOverlayReady(true);
+                    setThemeOverlayReady(userId);
                 }
             }, HOME_LAUNCH_TIMEOUT_MS);
         }
     }
 
     /**
-     * Used by ThemeOverlayController to notify all listeners for
-     * color palette readiness.
+     * Used by ThemeOverlayController to notify when color
+     * palette is ready.
+     *
+     * @param userId The ID of the user where ThemeOverlayController is ready.
+     *
+     * @throws RemoteException
+     *
      * @hide
      */
     @Override
-    public void setThemeOverlayReady(boolean readiness) {
+    public void setThemeOverlayReady(@UserIdInt int userId) {
         enforceCallingPermission(Manifest.permission.SET_THEME_OVERLAY_CONTROLLER_READY,
                 "setThemeOverlayReady");
 
-        int currentUserId = mUserController.getCurrentUserId();
-
-        boolean updateReadiness;
-        synchronized (mThemeOverlayReadiness) {
-            updateReadiness = readiness ? mThemeOverlayReadiness.add(currentUserId)
-                    : mThemeOverlayReadiness.remove(currentUserId);
+        boolean updateUser;
+        synchronized (mThemeOverlayReadyUsers) {
+            updateUser = mThemeOverlayReadyUsers.add(userId);
         }
 
-        if (updateReadiness && readiness && enableHomeDelay()) {
-            mAtmInternal.startHomeOnAllDisplays(currentUserId, "setThemeOverlayReady");
+        if (updateUser && enableHomeDelay()) {
+            mAtmInternal.startHomeOnAllDisplays(userId, "setThemeOverlayReady");
         }
     }
 
@@ -5370,10 +5373,9 @@
      *
      * @hide
      */
-    public boolean getThemeOverlayReadiness() {
-        int uid = mUserController.getCurrentUserId();
-        synchronized (mThemeOverlayReadiness) {
-            return mThemeOverlayReadiness.contains(uid);
+    public boolean isThemeOverlayReady(int userId) {
+        synchronized (mThemeOverlayReadyUsers) {
+            return mThemeOverlayReadyUsers.contains(userId);
         }
     }
 
@@ -18114,8 +18116,8 @@
             // Clean up various services by removing the user
             mBatteryStatsService.onUserRemoved(userId);
 
-            synchronized (mThemeOverlayReadiness) {
-                mThemeOverlayReadiness.remove(userId);
+            synchronized (mThemeOverlayReadyUsers) {
+                mThemeOverlayReadyUsers.remove(userId);
             }
         }
 
@@ -19477,8 +19479,8 @@
         }
 
         @Override
-        public boolean getThemeOverlayReadiness() {
-            return ActivityManagerService.this.getThemeOverlayReadiness();
+        public boolean isThemeOverlayReady(int userId) {
+            return ActivityManagerService.this.isThemeOverlayReady(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index e4956b3..0ce1407 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -2305,6 +2305,8 @@
                                     }
                                     ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
                                 }
+                                EventLogTags.writeAmCpu(st.pid, st.uid, st.baseName,
+                                        st.rel_uptime, st.rel_utime, st.rel_stime);
                             }
                         }
 
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 0f75ad48..8038732 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -127,6 +127,9 @@
 30102 am_foreground_service_stop (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3),(fgsType|1)
 30103 am_foreground_service_timed_out (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3),(fgsType|1)
 
+# Report collection of cpu used by a process
+30104 am_cpu (Pid|2|5),(UID|2|5),(Base Name|3),(Uptime|2|3),(Stime|2|3),(Utime|2|3)
+
 # Intent Sender redirect for UserHandle.USER_CURRENT
 30110 am_intent_sender_redirect_user (userId|1|5)
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index fca1199..0cc6494 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1241,15 +1241,15 @@
             Map<String, PackageState> packageStates) {
         synchronized (this) {
             // Remove what may have been added during persistence parsing
-            for (int i = mUidStates.size() - 1; i >= 0; i--) {
-                int uid = mUidStates.keyAt(i);
+            for (int uidIdx = mUidStates.size() - 1; uidIdx >= 0; uidIdx--) {
+                int uid = mUidStates.keyAt(uidIdx);
                 if (knownUids.get(uid, false)) {
                     if (uid >= Process.FIRST_APPLICATION_UID) {
-                        ArrayMap<String, Ops> pkgOps = mUidStates.valueAt(i).pkgOps;
-                        for (int j = 0; j < pkgOps.size(); j++) {
-                            String pkgName = pkgOps.keyAt(j);
+                        ArrayMap<String, Ops> pkgOps = mUidStates.valueAt(uidIdx).pkgOps;
+                        for (int pkgIdx = pkgOps.size() - 1; pkgIdx >= 0; pkgIdx--) {
+                            String pkgName = pkgOps.keyAt(pkgIdx);
                             if (!packageStates.containsKey(pkgName)) {
-                                pkgOps.removeAt(j);
+                                pkgOps.removeAt(pkgIdx);
                                 continue;
                             }
                             AndroidPackage pkg = packageStates.get(pkgName).getAndroidPackage();
@@ -1258,11 +1258,11 @@
                             }
                         }
                         if (pkgOps.isEmpty()) {
-                            mUidStates.remove(i);
+                            mUidStates.removeAt(uidIdx);
                         }
                     }
                 } else {
-                    mUidStates.removeAt(i);
+                    mUidStates.removeAt(uidIdx);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 559a1d6..ef93400 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -964,6 +964,8 @@
 
     private final HardeningEnforcer mHardeningEnforcer;
 
+    private final AudioVolumeGroupHelperBase mAudioVolumeGroupHelper;
+
     private final Object mSupportedSystemUsagesLock = new Object();
     @GuardedBy("mSupportedSystemUsagesLock")
     private @AttributeSystemUsage int[] mSupportedSystemUsages =
@@ -974,6 +976,13 @@
         return "card=" + card + ";device=" + device;
     }
 
+    private static class AudioVolumeGroupHelper extends AudioVolumeGroupHelperBase {
+        @Override
+        public List<AudioVolumeGroup> getAudioVolumeGroups() {
+            return AudioVolumeGroup.getAudioVolumeGroups();
+        }
+    }
+
     public static final class Lifecycle extends SystemService {
         private AudioService mService;
 
@@ -983,6 +992,7 @@
                               AudioSystemAdapter.getDefaultAdapter(),
                               SystemServerAdapter.getDefaultAdapter(context),
                               SettingsAdapter.getDefaultAdapter(),
+                              new AudioVolumeGroupHelper(),
                               new DefaultAudioPolicyFacade(),
                               null);
 
@@ -1062,16 +1072,19 @@
     /**
      * @param context
      * @param audioSystem Adapter for {@link AudioSystem}
-     * @param systemServer Adapter for privilieged functionality for system server components
+     * @param systemServer Adapter for privileged functionality for system server components
      * @param settings Adapter for {@link Settings}
+     * @param audioVolumeGroupHelper Adapter for {@link AudioVolumeGroup}
+     * @param audioPolicy Interface of a facade to IAudioPolicyManager
      * @param looper Looper to use for the service's message handler. If this is null, an
      *               {@link AudioSystemThread} is created as the messaging thread instead.
      */
     public AudioService(Context context, AudioSystemAdapter audioSystem,
             SystemServerAdapter systemServer, SettingsAdapter settings,
-            AudioPolicyFacade audioPolicy, @Nullable Looper looper) {
-        this (context, audioSystem, systemServer, settings, audioPolicy, looper,
-                context.getSystemService(AppOpsManager.class),
+            AudioVolumeGroupHelperBase audioVolumeGroupHelper, AudioPolicyFacade audioPolicy,
+            @Nullable Looper looper) {
+        this (context, audioSystem, systemServer, settings, audioVolumeGroupHelper,
+                audioPolicy, looper, context.getSystemService(AppOpsManager.class),
                 PermissionEnforcer.fromContext(context));
     }
 
@@ -1080,14 +1093,18 @@
      * @param audioSystem Adapter for {@link AudioSystem}
      * @param systemServer Adapter for privilieged functionality for system server components
      * @param settings Adapter for {@link Settings}
+     * @param audioVolumeGroupHelper Adapter for {@link AudioVolumeGroup}
+     * @param audioPolicy Interface of a facade to IAudioPolicyManager
      * @param looper Looper to use for the service's message handler. If this is null, an
      *               {@link AudioSystemThread} is created as the messaging thread instead.
+     * @param appOps {@link AppOpsManager} system service
+     * @param enforcer Used for permission enforcing
      */
     @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
     public AudioService(Context context, AudioSystemAdapter audioSystem,
             SystemServerAdapter systemServer, SettingsAdapter settings,
-            AudioPolicyFacade audioPolicy, @Nullable Looper looper, AppOpsManager appOps,
-            @NonNull PermissionEnforcer enforcer) {
+            AudioVolumeGroupHelperBase audioVolumeGroupHelper, AudioPolicyFacade audioPolicy,
+            @Nullable Looper looper, AppOpsManager appOps, @NonNull PermissionEnforcer enforcer) {
         super(enforcer);
         sLifecycleLogger.enqueue(new EventLogger.StringEvent("AudioService()"));
         mContext = context;
@@ -1096,6 +1113,7 @@
 
         mAudioSystem = audioSystem;
         mSystemServer = systemServer;
+        mAudioVolumeGroupHelper = audioVolumeGroupHelper;
         mSettings = settings;
         mAudioPolicy = audioPolicy;
         mPlatformType = AudioSystem.getPlatformType(context);
@@ -2104,7 +2122,7 @@
         // verify permissions
         super.getAudioVolumeGroups_enforcePermission();
 
-        return AudioVolumeGroup.getAudioVolumeGroups();
+        return mAudioVolumeGroupHelper.getAudioVolumeGroups();
     }
 
     private void checkAllAliasStreamVolumes() {
@@ -3803,7 +3821,7 @@
     }
 
     /**
-     * Loops on aliasted stream, update the mute cache attribute of each
+     * Loops on aliased stream, update the mute cache attribute of each
      * {@see AudioService#VolumeStreamState}, and then apply the change.
      * It prevents to unnecessary {@see AudioSystem#setStreamVolume} done for each stream
      * and aliases before mute change changed and after.
@@ -4040,18 +4058,6 @@
         }
     }
 
-    @Nullable
-    private AudioVolumeGroup getAudioVolumeGroupById(int volumeGroupId) {
-        for (AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) {
-            if (avg.getId() == volumeGroupId) {
-                return avg;
-            }
-        }
-
-        Log.e(TAG, ": invalid volume group id: " + volumeGroupId + " requested");
-        return null;
-    }
-
     @Override
     @android.annotation.EnforcePermission(anyOf = {
             MODIFY_AUDIO_SETTINGS_PRIVILEGED,
@@ -8252,7 +8258,7 @@
                 index = 1;
             }
             // Set the volume index
-            AudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
+            mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
         }
 
         @GuardedBy("AudioService.VolumeStreamState.class")
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 49ab19a..7202fa2 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -551,6 +551,11 @@
         return AudioSystem.setStreamVolumeIndexAS(stream, index, device);
     }
 
+    /** Same as {@link AudioSystem#setVolumeIndexForAttributes(AudioAttributes, int, int)} */
+    public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, int device) {
+        return AudioSystem.setVolumeIndexForAttributes(attributes, index, device);
+    }
+
     /**
      * Same as {@link AudioSystem#setPhoneState(int, int)}
      * @param state
diff --git a/services/core/java/com/android/server/audio/AudioVolumeGroupHelperBase.java b/services/core/java/com/android/server/audio/AudioVolumeGroupHelperBase.java
new file mode 100644
index 0000000..6f4de5bc
--- /dev/null
+++ b/services/core/java/com/android/server/audio/AudioVolumeGroupHelperBase.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.audio;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.media.audiopolicy.AudioVolumeGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Abstract class for {@link AudioVolumeGroup} related helper methods. */
+@VisibleForTesting(visibility = PACKAGE)
+public class AudioVolumeGroupHelperBase {
+    public List<AudioVolumeGroup> getAudioVolumeGroups() {
+        return new ArrayList<>();
+    }
+}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
index fab769e..40e9198 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
@@ -75,6 +75,6 @@
     protected enum Type {
         THERMAL,
         POWER,
-        BEDTIME_MODE,
+        WEAR_BEDTIME_MODE,
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index 2c02fc6..bc5fcb4 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -156,6 +156,8 @@
             return BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
         } else if (mClamperType == Type.POWER) {
             return BrightnessInfo.BRIGHTNESS_MAX_REASON_POWER_IC;
+        } else if (mClamperType == Type.WEAR_BEDTIME_MODE) {
+            return BrightnessInfo.BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE;
         } else {
             Slog.wtf(TAG, "BrightnessMaxReason not mapped for type=" + mClamperType);
             return BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java
index 7e853bf..1902e35 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamper.java
@@ -64,7 +64,7 @@
     @NonNull
     @Override
     Type getType() {
-        return Type.BEDTIME_MODE;
+        return Type.WEAR_BEDTIME_MODE;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
index 6a6e6ab..c2c82ed 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionManagerInternal.java
@@ -16,6 +16,7 @@
 
 package com.android.server.grammaticalinflection;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Configuration;
 
@@ -55,11 +56,11 @@
      *
      */
     public abstract @Configuration.GrammaticalGender int retrieveSystemGrammaticalGender(
-            Configuration configuration);
+            @NonNull Configuration configuration);
 
     /**
      * Whether the package can get the system grammatical gender or not.
      */
-    public abstract boolean canGetSystemGrammaticalGender(int uid, String packageName);
+    public abstract boolean canGetSystemGrammaticalGender(int uid, @Nullable String packageName);
 }
 
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index d01f54f..0bcb26d 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -329,8 +329,9 @@
 
     private void checkCallerIsSystem() {
         int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SYSTEM_UID && callingUid != Process.SHELL_UID) {
-            throw new SecurityException("Caller is not system and shell.");
+        if (callingUid != Process.SYSTEM_UID && callingUid != Process.SHELL_UID
+                && callingUid != Process.ROOT_UID) {
+            throw new SecurityException("Caller is not system, shell and root.");
         }
     }
 
@@ -354,12 +355,11 @@
             final File file = getGrammaticalGenderFile(userId);
             synchronized (mLock) {
                 if (!file.exists()) {
-                    Log.d(TAG, "User " + userId + "doesn't have the grammatical gender file.");
+                    Log.d(TAG, "User " + userId + " doesn't have the grammatical gender file.");
                     return;
                 }
                 if (mGrammaticalGenderCache.indexOfKey(userId) < 0) {
-                    try {
-                        InputStream in = new FileInputStream(file);
+                    try (FileInputStream in = new FileInputStream(file)) {
                         final TypedXmlPullParser parser = Xml.resolvePullParser(in);
                         mGrammaticalGenderCache.put(userId, getGrammaticalGenderFromXml(parser));
                     } catch (IOException | XmlPullParserException e) {
diff --git a/services/core/java/com/android/server/input/debug/FocusEventDebugView.java b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
index 6eec0de..3ffd2e1 100644
--- a/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
+++ b/services/core/java/com/android/server/input/debug/FocusEventDebugView.java
@@ -34,6 +34,7 @@
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.InputDevice;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.RoundedCorner;
@@ -335,7 +336,15 @@
 
         final int unicodeChar = event.getUnicodeChar();
         if (unicodeChar != 0) {
-            return new String(Character.toChars(unicodeChar));
+            if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+                // Show combining character
+                final int combiningChar = KeyCharacterMap.getCombiningChar(
+                        unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK);
+                // Return the Unicode dotted circle as part of the label as it is used is used to
+                // illustrate the effect of a combining marks
+                return "\u25cc" + String.valueOf((char) combiningChar);
+            }
+            return String.valueOf((char) unicodeChar);
         }
 
         final var label = KeyEvent.keyCodeToString(event.getKeyCode());
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java
index 977dbff..84a59b4 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java
@@ -117,6 +117,30 @@
     }
 
     @AnyThread
+    void onStartInputResult(@NonNull InputBindResult res, int startInputSeq) {
+        if (mIsProxy) {
+            onStartInputResultInternal(res, startInputSeq);
+        } else {
+            mHandler.post(() -> onStartInputResultInternal(res, startInputSeq));
+        }
+    }
+
+    @AnyThread
+    private void onStartInputResultInternal(@NonNull InputBindResult res, int startInputSeq) {
+        try {
+            mTarget.onStartInputResult(res, startInputSeq);
+        } catch (RemoteException e) {
+            logRemoteException(e);
+        } finally {
+            // Dispose the channel if the input method is not local to this process
+            // because the remote proxy will get its own copy when unparceled.
+            if (res.channel != null && mIsProxy) {
+                res.channel.dispose();
+            }
+        }
+    }
+
+    @AnyThread
     void onBindAccessibilityService(@NonNull InputBindResult res, int id) {
         if (mIsProxy) {
             onBindAccessibilityServiceInternal(res, id);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index bc169ca..5574d18 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1539,7 +1539,13 @@
         @Override
         public void onStart() {
             mService.publishLocalService();
-            publishBinderService(Context.INPUT_METHOD_SERVICE, mService, false /*allowIsolated*/,
+            IInputMethodManager.Stub service;
+            if (Flags.useZeroJankProxy()) {
+                service = new ZeroJankProxy(mService.mHandler::post, mService);
+            } else {
+                service = mService;
+            }
+            publishBinderService(Context.INPUT_METHOD_SERVICE, service, false /*allowIsolated*/,
                     DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
         }
 
@@ -2216,6 +2222,14 @@
         }
     }
 
+    @Nullable
+    ClientState getClientState(IInputMethodClient client) {
+        synchronized (ImfLock.class) {
+            return mClientController.getClient(client.asBinder());
+        }
+    }
+
+    // TODO(b/314150112): Move this to ClientController.
     @GuardedBy("ImfLock.class")
     void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
         if (mCurClient != null) {
@@ -3741,6 +3755,20 @@
         return imeClientFocus == WindowManagerInternal.ImeClientFocusResult.HAS_IME_FOCUS;
     }
 
+    //TODO(b/293640003): merge with startInputOrWindowGainedFocus once Flags.useZeroJankProxy()
+    // is enabled.
+    @Override
+    public void startInputOrWindowGainedFocusAsync(
+            @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
+            @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
+            int windowFlags, @Nullable EditorInfo editorInfo,
+            IRemoteInputConnection inputConnection,
+            IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
+            int unverifiedTargetSdkVersion, @UserIdInt int userId,
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) {
+        // implemented by ZeroJankProxy
+    }
+
     @NonNull
     @Override
     public InputBindResult startInputOrWindowGainedFocus(
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
new file mode 100644
index 0000000..692fd7dc
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import static com.android.server.inputmethod.InputMethodManagerService.TAG;
+
+import android.Manifest;
+import android.annotation.BinderThread;
+import android.annotation.EnforcePermission;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.util.ExceptionUtils;
+import android.util.Slog;
+import android.view.WindowManager;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+import android.window.ImeOnBackInvokedDispatcher;
+
+import com.android.internal.inputmethod.DirectBootAwareness;
+import com.android.internal.inputmethod.IConnectionlessHandwritingCallback;
+import com.android.internal.inputmethod.IImeTracker;
+import com.android.internal.inputmethod.IInputMethodClient;
+import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
+import com.android.internal.inputmethod.IRemoteInputConnection;
+import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.inputmethod.StartInputFlags;
+import com.android.internal.inputmethod.StartInputReason;
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.view.IInputMethodManager;
+
+import java.io.FileDescriptor;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+/**
+ * A proxy that processes all {@link IInputMethodManager} calls asynchronously.
+ * @hide
+ */
+public class ZeroJankProxy extends IInputMethodManager.Stub {
+
+    private final IInputMethodManager mInner;
+    private final Executor mExecutor;
+
+    ZeroJankProxy(Executor executor, IInputMethodManager inner) {
+        mInner = inner;
+        mExecutor = executor;
+    }
+
+    private void offload(ThrowingRunnable r) {
+        offloadInner(r);
+    }
+
+    private void offload(Runnable r) {
+        offloadInner(r);
+    }
+
+    private void offloadInner(Runnable r) {
+        boolean useThrowingRunnable = r instanceof ThrowingRunnable;
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mExecutor.execute(() -> {
+                final long inner = Binder.clearCallingIdentity();
+                // Restoring calling identity, so we can still do permission checks on caller.
+                Binder.restoreCallingIdentity(identity);
+                try {
+                    try {
+                        if (useThrowingRunnable) {
+                            ((ThrowingRunnable) r).runOrThrow();
+                        } else {
+                            r.run();
+                        }
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Error in async call", e);
+                        throw ExceptionUtils.propagate(e);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(inner);
+                }
+            });
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void addClient(IInputMethodClient client, IRemoteInputConnection inputConnection,
+            int selfReportedDisplayId) throws RemoteException {
+        offload(() -> mInner.addClient(client, inputConnection, selfReportedDisplayId));
+    }
+
+    @Override
+    public InputMethodInfo getCurrentInputMethodInfoAsUser(int userId) throws RemoteException {
+        return mInner.getCurrentInputMethodInfoAsUser(userId);
+    }
+
+    @Override
+    public List<InputMethodInfo> getInputMethodList(
+            int userId, @DirectBootAwareness int directBootAwareness) throws RemoteException {
+        return mInner.getInputMethodList(userId, directBootAwareness);
+    }
+
+    @Override
+    public List<InputMethodInfo> getEnabledInputMethodList(int userId) throws RemoteException {
+        return mInner.getEnabledInputMethodList(userId);
+    }
+
+    @Override
+    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
+            boolean allowsImplicitlyEnabledSubtypes, int userId)
+            throws RemoteException {
+        return mInner.getEnabledInputMethodSubtypeList(imiId, allowsImplicitlyEnabledSubtypes,
+                userId);
+    }
+
+    @Override
+    public InputMethodSubtype getLastInputMethodSubtype(int userId) throws RemoteException {
+        return mInner.getLastInputMethodSubtype(userId);
+    }
+
+    @Override
+    public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
+            @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+            int lastClickTooType, ResultReceiver resultReceiver,
+            @SoftInputShowHideReason int reason)
+            throws RemoteException {
+        offload(() -> mInner.showSoftInput(client, windowToken, statsToken, flags, lastClickTooType,
+                resultReceiver, reason));
+        return true;
+    }
+
+    @Override
+    public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
+            @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
+            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)
+            throws RemoteException {
+        offload(() -> mInner.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver,
+                reason));
+        return true;
+    }
+
+    @Override
+    public void startInputOrWindowGainedFocusAsync(
+            @StartInputReason int startInputReason,
+            IInputMethodClient client, IBinder windowToken,
+            @StartInputFlags int startInputFlags,
+            @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode,
+            int windowFlags, @Nullable EditorInfo editorInfo,
+            IRemoteInputConnection inputConnection,
+            IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
+            int unverifiedTargetSdkVersion, @UserIdInt int userId,
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq)
+            throws RemoteException {
+        offload(() -> {
+            InputBindResult result = mInner.startInputOrWindowGainedFocus(startInputReason, client,
+                    windowToken, startInputFlags, softInputMode, windowFlags,
+                    editorInfo,
+                    inputConnection, remoteAccessibilityInputConnection,
+                    unverifiedTargetSdkVersion,
+                    userId, imeDispatcher);
+            sendOnStartInputResult(client, result, startInputSeq);
+        });
+    }
+
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    @Override
+    public InputBindResult startInputOrWindowGainedFocus(
+            @StartInputReason int startInputReason,
+            IInputMethodClient client, IBinder windowToken,
+            @StartInputFlags int startInputFlags,
+            @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode,
+            int windowFlags, @Nullable EditorInfo editorInfo,
+            IRemoteInputConnection inputConnection,
+            IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
+            int unverifiedTargetSdkVersion, @UserIdInt int userId,
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher)
+            throws RemoteException {
+        // Should never be called when flag is enabled i.e. when this proxy is used.
+        return null;
+    }
+
+    @Override
+    public void showInputMethodPickerFromClient(IInputMethodClient client,
+            int auxiliarySubtypeMode)
+            throws RemoteException {
+        offload(() -> mInner.showInputMethodPickerFromClient(client, auxiliarySubtypeMode));
+    }
+
+    @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    @Override
+    public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId)
+            throws RemoteException {
+        mInner.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId);
+    }
+
+    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
+    @Override
+    public boolean isInputMethodPickerShownForTest() throws RemoteException {
+        super.isInputMethodPickerShownForTest_enforcePermission();
+        return mInner.isInputMethodPickerShownForTest();
+    }
+
+    @Override
+    public InputMethodSubtype getCurrentInputMethodSubtype(int userId) throws RemoteException {
+        return mInner.getCurrentInputMethodSubtype(userId);
+    }
+
+    @Override
+    public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes,
+            @UserIdInt int userId) throws RemoteException {
+        mInner.setAdditionalInputMethodSubtypes(imiId, subtypes, userId);
+    }
+
+    @Override
+    public void setExplicitlyEnabledInputMethodSubtypes(String imeId,
+            @NonNull int[] subtypeHashCodes, @UserIdInt int userId) throws RemoteException {
+        mInner.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId);
+    }
+
+    @Override
+    public int getInputMethodWindowVisibleHeight(IInputMethodClient client)
+            throws RemoteException {
+        return mInner.getInputMethodWindowVisibleHeight(client);
+    }
+
+    @Override
+    public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible)
+            throws RemoteException {
+        // Already async TODO(b/293640003): ordering issues?
+        mInner.reportPerceptibleAsync(windowToken, perceptible);
+    }
+
+    @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW)
+    @Override
+    public void removeImeSurface() throws RemoteException {
+        mInner.removeImeSurface();
+    }
+
+    @Override
+    public void removeImeSurfaceFromWindowAsync(IBinder windowToken) throws RemoteException {
+        mInner.removeImeSurfaceFromWindowAsync(windowToken);
+    }
+
+    @Override
+    public void startProtoDump(byte[] bytes, int i, String s) throws RemoteException {
+        mInner.startProtoDump(bytes, i, s);
+    }
+
+    @Override
+    public boolean isImeTraceEnabled() throws RemoteException {
+        return mInner.isImeTraceEnabled();
+    }
+
+    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING)
+    @Override
+    public void startImeTrace() throws RemoteException {
+        mInner.startImeTrace();
+    }
+
+    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING)
+    @Override
+    public void stopImeTrace() throws RemoteException {
+        mInner.stopImeTrace();
+    }
+
+    @Override
+    public void startStylusHandwriting(IInputMethodClient client)
+            throws RemoteException {
+        offload(() -> mInner.startStylusHandwriting(client));
+    }
+
+    @Override
+    public void startConnectionlessStylusHandwriting(IInputMethodClient client, int userId,
+            @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName,
+            @Nullable String delegatorPackageName,
+            @NonNull IConnectionlessHandwritingCallback callback) throws RemoteException {
+        offload(() -> mInner.startConnectionlessStylusHandwriting(
+                client, userId, cursorAnchorInfo, delegatePackageName, delegatorPackageName,
+                callback));
+    }
+
+    @Override
+    public boolean acceptStylusHandwritingDelegation(
+            @NonNull IInputMethodClient client,
+            @UserIdInt int userId,
+            @NonNull String delegatePackageName,
+            @NonNull String delegatorPackageName,
+            @InputMethodManager.HandwritingDelegateFlags int flags) {
+        try {
+            return CompletableFuture.supplyAsync(() -> {
+                try {
+                    return mInner.acceptStylusHandwritingDelegation(
+                            client, userId, delegatePackageName, delegatorPackageName, flags);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }, this::offload).get();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void prepareStylusHandwritingDelegation(
+            @NonNull IInputMethodClient client,
+            @UserIdInt int userId,
+            @NonNull String delegatePackageName,
+            @NonNull String delegatorPackageName) {
+        offload(() -> mInner.prepareStylusHandwritingDelegation(
+                client, userId, delegatePackageName, delegatorPackageName));
+    }
+
+    @Override
+    public boolean isStylusHandwritingAvailableAsUser(int userId, boolean connectionless)
+            throws RemoteException {
+        return mInner.isStylusHandwritingAvailableAsUser(userId, connectionless);
+    }
+
+    @EnforcePermission("android.permission.TEST_INPUT_METHOD")
+    @Override
+    public void addVirtualStylusIdForTestSession(IInputMethodClient client)
+            throws RemoteException {
+        mInner.addVirtualStylusIdForTestSession(client);
+    }
+
+    @EnforcePermission("android.permission.TEST_INPUT_METHOD")
+    @Override
+    public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout)
+            throws RemoteException {
+        mInner.setStylusWindowIdleTimeoutForTest(client, timeout);
+    }
+
+    @Override
+    public IImeTracker getImeTrackerService() throws RemoteException {
+        return mInner.getImeTrackerService();
+    }
+
+    @BinderThread
+    @Override
+    public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+            @Nullable FileDescriptor err,
+            @NonNull String[] args, @Nullable ShellCallback callback,
+            @NonNull ResultReceiver resultReceiver) throws RemoteException {
+        ((InputMethodManagerService) mInner).onShellCommand(
+                in, out, err, args, callback, resultReceiver);
+    }
+
+    private void sendOnStartInputResult(
+            IInputMethodClient client, InputBindResult res, int startInputSeq) {
+        InputMethodManagerService service = (InputMethodManagerService) mInner;
+        final ClientState cs = service.getClientState(client);
+        if (cs != null && cs.mClient != null) {
+            cs.mClient.onStartInputResult(res, startInputSeq);
+        } else {
+            // client is unbound.
+            Slog.i(TAG, "Client that requested startInputOrWindowGainedFocus is no longer"
+                    + " bound. InputBindResult: " + res + " for startInputSeq: " + startInputSeq);
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index f97f6d2..3e8af27 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -105,7 +105,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -154,7 +153,7 @@
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
 
     /* Maps uid with all user engaging session tokens associated to it */
-    private final Map<Integer, Set<MediaSession.Token>> mUserEngagingSessions = new HashMap<>();
+    private final SparseArray<Set<MediaSession.Token>> mUserEngagingSessions = new SparseArray<>();
 
     // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
     // It's always not null after the MediaSessionService is started.
@@ -625,29 +624,27 @@
 
         String packageName = record.getPackageName();
         int sessionUid = record.getUid();
-        String actionToLog = null;
         MediaSession.Token token = ((MediaSessionRecord) record).getSessionToken();
         if (userEngaged) {
-            if (!mUserEngagingSessions.containsKey(sessionUid)) {
+            if (!mUserEngagingSessions.contains(sessionUid)) {
                 mUserEngagingSessions.put(sessionUid, new HashSet<>());
-                actionToLog = "start";
+                reportUserInteractionEvent(/* action= */ "start", record.getUserId(), packageName);
             }
             mUserEngagingSessions.get(sessionUid).add(token);
-        } else if (mUserEngagingSessions.containsKey(sessionUid)) {
+        } else if (mUserEngagingSessions.contains(sessionUid)) {
             mUserEngagingSessions.get(sessionUid).remove(token);
             if (mUserEngagingSessions.get(sessionUid).isEmpty()) {
-                actionToLog = "stop";
+                reportUserInteractionEvent(/* action= */ "stop", record.getUserId(), packageName);
                 mUserEngagingSessions.remove(sessionUid);
             }
         }
+    }
 
-        if (actionToLog != null) {
-            PersistableBundle extras = new PersistableBundle();
-            extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.media");
-            extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, actionToLog);
-            mUsageStatsManagerInternal.reportUserInteractionEvent(
-                    packageName, record.getUserId(), extras);
-        }
+    private void reportUserInteractionEvent(String action, int userId, String packageName) {
+        PersistableBundle extras = new PersistableBundle();
+        extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.media");
+        extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, action);
+        mUsageStatsManagerInternal.reportUserInteractionEvent(packageName, userId, extras);
     }
 
     void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
diff --git a/services/core/java/com/android/server/notification/Android.bp b/services/core/java/com/android/server/notification/Android.bp
index f26a25b..9be4358 100644
--- a/services/core/java/com/android/server/notification/Android.bp
+++ b/services/core/java/com/android/server/notification/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
+}
+
 java_aconfig_library {
     name: "notification_flags_lib",
     aconfig_declarations: "notification_flags",
@@ -9,4 +13,4 @@
     srcs: [
         "flags.aconfig",
     ],
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
new file mode 100644
index 0000000..a4c4347
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ondeviceintelligence;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.app.AppGlobals;
+import android.app.ondeviceintelligence.Content;
+import android.app.ondeviceintelligence.DownloadCallback;
+import android.app.ondeviceintelligence.Feature;
+import android.app.ondeviceintelligence.IDownloadCallback;
+import android.app.ondeviceintelligence.IFeatureCallback;
+import android.app.ondeviceintelligence.IFeatureDetailsCallback;
+import android.app.ondeviceintelligence.IListFeaturesCallback;
+import android.app.ondeviceintelligence.IOnDeviceIntelligenceManager;
+import android.app.ondeviceintelligence.IProcessingSignal;
+import android.app.ondeviceintelligence.IResponseCallback;
+import android.app.ondeviceintelligence.IStreamingResponseCallback;
+import android.app.ondeviceintelligence.ITokenCountCallback;
+import android.app.ondeviceintelligence.OnDeviceIntelligenceManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.ICancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.service.ondeviceintelligence.IOnDeviceTrustedInferenceService;
+import android.service.ondeviceintelligence.IRemoteStorageService;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.SystemService;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This is the system service for handling calls on the {@link OnDeviceIntelligenceManager}. This
+ * service holds connection references to the underlying remote services i.e. the isolated service
+ * {@link android.service.ondeviceintelligence.OnDeviceTrustedInferenceService} and a regular
+ * service counter part {@link android.service.ondeviceintelligence.OnDeviceIntelligenceService}.
+ *
+ * Note: Both the remote services run under the SYSTEM user, as we cannot have separate instance of
+ * the Inference service for each user, due to possible high memory footprint.
+ *
+ * @hide
+ */
+public class OnDeviceIntelligenceManagerService extends SystemService {
+
+    private static final String TAG = OnDeviceIntelligenceManagerService.class.getSimpleName();
+    private static final String KEY_SERVICE_ENABLED = "service_enabled";
+
+    /** Default value in absence of {@link DeviceConfig} override. */
+    private static final boolean DEFAULT_SERVICE_ENABLED = true;
+    private static final String NAMESPACE_ON_DEVICE_INTELLIGENCE = "ondeviceintelligence";
+
+    private final Context mContext;
+    protected final Object mLock = new Object();
+
+
+    private RemoteOnDeviceTrustedInferenceService mRemoteInferenceService;
+    private RemoteOnDeviceIntelligenceService mRemoteOnDeviceIntelligenceService;
+    volatile boolean mIsServiceEnabled;
+
+    public OnDeviceIntelligenceManagerService(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(
+                Context.ON_DEVICE_INTELLIGENCE_SERVICE, new OnDeviceIntelligenceManagerInternal(),
+                /* allowIsolated = */true);
+    }
+
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            DeviceConfig.addOnPropertiesChangedListener(
+                    NAMESPACE_ON_DEVICE_INTELLIGENCE,
+                    BackgroundThread.getExecutor(),
+                    (properties) -> onDeviceConfigChange(properties.getKeyset()));
+
+            mIsServiceEnabled = isServiceEnabled();
+        }
+    }
+
+    private void onDeviceConfigChange(@NonNull Set<String> keys) {
+        if (keys.contains(KEY_SERVICE_ENABLED)) {
+            mIsServiceEnabled = isServiceEnabled();
+        }
+    }
+
+    private boolean isServiceEnabled() {
+        return DeviceConfig.getBoolean(
+                NAMESPACE_ON_DEVICE_INTELLIGENCE,
+                KEY_SERVICE_ENABLED, DEFAULT_SERVICE_ENABLED);
+    }
+
+    private final class OnDeviceIntelligenceManagerInternal extends
+            IOnDeviceIntelligenceManager.Stub {
+        @Override
+        public void getVersion(RemoteCallback remoteCallback) throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal getVersion");
+            Objects.requireNonNull(remoteCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                remoteCallback.sendResult(null);
+                return;
+            }
+            ensureRemoteIntelligenceServiceInitialized();
+            mRemoteOnDeviceIntelligenceService.post(
+                    service -> service.getVersion(remoteCallback));
+        }
+
+        @Override
+        public void getFeature(int id, IFeatureCallback featureCallback) throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal getFeatures");
+            Objects.requireNonNull(featureCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                featureCallback.onFailure(
+                        OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException.ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+                return;
+            }
+            ensureRemoteIntelligenceServiceInitialized();
+            mRemoteOnDeviceIntelligenceService.post(
+                    service -> service.getFeature(id, featureCallback));
+        }
+
+        @Override
+        public void listFeatures(IListFeaturesCallback listFeaturesCallback)
+                throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal getFeatures");
+            Objects.requireNonNull(listFeaturesCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                listFeaturesCallback.onFailure(
+                        OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException.ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+                return;
+            }
+            ensureRemoteIntelligenceServiceInitialized();
+            mRemoteOnDeviceIntelligenceService.post(
+                    service -> service.listFeatures(listFeaturesCallback));
+        }
+
+        @Override
+        public void getFeatureDetails(Feature feature,
+                IFeatureDetailsCallback featureDetailsCallback)
+                throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal getFeatureStatus");
+            Objects.requireNonNull(feature);
+            Objects.requireNonNull(featureDetailsCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                featureDetailsCallback.onFailure(
+                        OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException.ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+                return;
+            }
+            ensureRemoteIntelligenceServiceInitialized();
+            mRemoteOnDeviceIntelligenceService.post(
+                    service -> service.getFeatureDetails(feature, featureDetailsCallback));
+        }
+
+        @Override
+        public void requestFeatureDownload(Feature feature, ICancellationSignal cancellationSignal,
+                IDownloadCallback downloadCallback) throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal requestFeatureDownload");
+            Objects.requireNonNull(feature);
+            Objects.requireNonNull(downloadCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                downloadCallback.onDownloadFailed(
+                        DownloadCallback.DOWNLOAD_FAILURE_STATUS_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+            }
+            ensureRemoteIntelligenceServiceInitialized();
+            mRemoteOnDeviceIntelligenceService.post(
+                    service -> service.requestFeatureDownload(feature, cancellationSignal,
+                            downloadCallback));
+        }
+
+
+        @Override
+        public void requestTokenCount(Feature feature,
+                Content request, ICancellationSignal cancellationSignal,
+                ITokenCountCallback tokenCountcallback) throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal prepareFeatureProcessing");
+            Objects.requireNonNull(feature);
+            Objects.requireNonNull(request);
+            Objects.requireNonNull(tokenCountcallback);
+
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                tokenCountcallback.onFailure(
+                        OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException.ON_DEVICE_INTELLIGENCE_SERVICE_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+            }
+            ensureRemoteTrustedInferenceServiceInitialized();
+            mRemoteInferenceService.post(
+                    service -> service.requestTokenCount(feature, request, cancellationSignal,
+                            tokenCountcallback));
+        }
+
+        @Override
+        public void processRequest(Feature feature,
+                Content request,
+                int requestType,
+                ICancellationSignal cancellationSignal,
+                IProcessingSignal processingSignal,
+                IResponseCallback responseCallback)
+                throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal processRequest");
+            Objects.requireNonNull(feature);
+            Objects.requireNonNull(responseCallback);
+            Objects.requireNonNull(request);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                responseCallback.onFailure(
+                        OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException.PROCESSING_ERROR_SERVICE_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+            }
+            ensureRemoteTrustedInferenceServiceInitialized();
+            mRemoteInferenceService.post(
+                    service -> service.processRequest(feature, request, requestType,
+                            cancellationSignal, processingSignal,
+                            responseCallback));
+        }
+
+        @Override
+        public void processRequestStreaming(Feature feature,
+                Content request,
+                int requestType,
+                ICancellationSignal cancellationSignal,
+                IProcessingSignal processingSignal,
+                IStreamingResponseCallback streamingCallback) throws RemoteException {
+            Slog.i(TAG, "OnDeviceIntelligenceManagerInternal processRequestStreaming");
+            Objects.requireNonNull(feature);
+            Objects.requireNonNull(request);
+            Objects.requireNonNull(streamingCallback);
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+            if (!mIsServiceEnabled) {
+                Slog.w(TAG, "Service not available");
+                streamingCallback.onFailure(
+                        OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException.PROCESSING_ERROR_SERVICE_UNAVAILABLE,
+                        "OnDeviceIntelligenceManagerService is unavailable",
+                        new PersistableBundle());
+            }
+            ensureRemoteTrustedInferenceServiceInitialized();
+            mRemoteInferenceService.post(
+                    service -> service.processRequestStreaming(feature, request, requestType,
+                            cancellationSignal, processingSignal,
+                            streamingCallback));
+        }
+    }
+
+    private void ensureRemoteIntelligenceServiceInitialized() throws RemoteException {
+        synchronized (mLock) {
+            if (mRemoteOnDeviceIntelligenceService == null) {
+                String serviceName = mContext.getResources().getString(
+                        R.string.config_defaultOnDeviceIntelligenceService);
+                validateService(serviceName, false);
+                mRemoteOnDeviceIntelligenceService = new RemoteOnDeviceIntelligenceService(mContext,
+                        ComponentName.unflattenFromString(serviceName),
+                        UserHandle.SYSTEM.getIdentifier());
+            }
+        }
+    }
+
+    private void ensureRemoteTrustedInferenceServiceInitialized() throws RemoteException {
+        synchronized (mLock) {
+            if (mRemoteInferenceService == null) {
+                String serviceName = mContext.getResources().getString(
+                        R.string.config_defaultOnDeviceTrustedInferenceService);
+                validateService(serviceName, true);
+                mRemoteInferenceService = new RemoteOnDeviceTrustedInferenceService(mContext,
+                        ComponentName.unflattenFromString(serviceName),
+                        UserHandle.SYSTEM.getIdentifier());
+                mRemoteInferenceService.setServiceLifecycleCallbacks(
+                        new ServiceConnector.ServiceLifecycleCallbacks<>() {
+                            @Override
+                            public void onConnected(
+                                    @NonNull IOnDeviceTrustedInferenceService service) {
+                                try {
+                                    service.registerRemoteStorageService(
+                                            getIRemoteStorageService());
+                                } catch (RemoteException ex) {
+                                    Slog.w(TAG, "Failed to send connected event", ex);
+                                }
+                            }
+                        });
+            }
+        }
+    }
+
+    @NonNull
+    private IRemoteStorageService.Stub getIRemoteStorageService() {
+        return new IRemoteStorageService.Stub() {
+            @Override
+            public void getReadOnlyFileDescriptor(
+                    String filePath,
+                    AndroidFuture<ParcelFileDescriptor> future) {
+                mRemoteOnDeviceIntelligenceService.post(
+                        service -> service.getReadOnlyFileDescriptor(
+                                filePath, future));
+            }
+
+            @Override
+            public void getReadOnlyFeatureFileDescriptorMap(
+                    Feature feature,
+                    RemoteCallback remoteCallback)
+                    throws RemoteException {
+                mRemoteOnDeviceIntelligenceService.post(
+                        service -> service.getReadOnlyFeatureFileDescriptorMap(
+                                feature, remoteCallback));
+            }
+        };
+    }
+
+    @GuardedBy("mLock")
+    private void validateService(String serviceName, boolean checkIsolated)
+            throws RemoteException {
+        if (TextUtils.isEmpty(serviceName)) {
+            throw new RuntimeException("");
+        }
+        ComponentName serviceComponent = ComponentName.unflattenFromString(
+                serviceName);
+        ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
+                serviceComponent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 0);
+        if (serviceInfo != null) {
+            if (!checkIsolated) {
+                checkServiceRequiresPermission(serviceInfo,
+                        Manifest.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE);
+                return;
+            }
+
+            checkServiceRequiresPermission(serviceInfo,
+                    Manifest.permission.BIND_ON_DEVICE_TRUSTED_SERVICE);
+            if (!isIsolatedService(serviceInfo)) {
+                throw new SecurityException(
+                        "Call required an isolated service, but the configured service: "
+                                + serviceName + ", is not isolated");
+            }
+        } else {
+            throw new RuntimeException(
+                    "Could not find service info for serviceName: " + serviceName);
+        }
+    }
+
+    private static void checkServiceRequiresPermission(ServiceInfo serviceInfo,
+            String requiredPermission) {
+        final String permission = serviceInfo.permission;
+        if (!requiredPermission.equals(permission)) {
+            throw new SecurityException(String.format(
+                    "Service %s requires %s permission. Found %s permission",
+                    serviceInfo.getComponentName(),
+                    requiredPermission,
+                    serviceInfo.permission));
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean isIsolatedService(@NonNull ServiceInfo serviceInfo) {
+        return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
+                && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
+    }
+}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
new file mode 100644
index 0000000..48258d7
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceIntelligenceService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ondeviceintelligence;
+
+import static android.content.Context.BIND_FOREGROUND_SERVICE;
+import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.service.ondeviceintelligence.IOnDeviceIntelligenceService;
+import android.service.ondeviceintelligence.OnDeviceIntelligenceService;
+
+import com.android.internal.infra.ServiceConnector;
+
+/**
+ * Manages the connection to the remote on-device intelligence service. Also, handles unbinding
+ * logic set by the service implementation via a Secure Settings flag.
+ */
+public class RemoteOnDeviceIntelligenceService extends
+        ServiceConnector.Impl<IOnDeviceIntelligenceService> {
+    private static final String TAG =
+            RemoteOnDeviceIntelligenceService.class.getSimpleName();
+
+    RemoteOnDeviceIntelligenceService(Context context, ComponentName serviceName,
+            int userId) {
+        super(context, new Intent(
+                        OnDeviceIntelligenceService.SERVICE_INTERFACE).setComponent(serviceName),
+                BIND_FOREGROUND_SERVICE | BIND_INCLUDE_CAPABILITIES, userId,
+                IOnDeviceIntelligenceService.Stub::asInterface);
+
+        // Bind right away
+        connect();
+    }
+
+    @Override
+    protected long getAutoDisconnectTimeoutMs() {
+        // Disable automatic unbinding.
+        // TODO: add logic to fetch this flag via SecureSettings.
+        return -1;
+    }
+}
diff --git a/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceTrustedInferenceService.java b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceTrustedInferenceService.java
new file mode 100644
index 0000000..cc8e788
--- /dev/null
+++ b/services/core/java/com/android/server/ondeviceintelligence/RemoteOnDeviceTrustedInferenceService.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ondeviceintelligence;
+
+import static android.content.Context.BIND_FOREGROUND_SERVICE;
+import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.service.ondeviceintelligence.IOnDeviceTrustedInferenceService;
+import android.service.ondeviceintelligence.OnDeviceTrustedInferenceService;
+
+import com.android.internal.infra.ServiceConnector;
+
+
+/**
+ * Manages the connection to the remote on-device trusted inference service. Also, handles unbinding
+ * logic set by the service implementation via a SecureSettings flag.
+ */
+public class RemoteOnDeviceTrustedInferenceService extends
+        ServiceConnector.Impl<IOnDeviceTrustedInferenceService> {
+    /**
+     * Creates an instance of {@link ServiceConnector}
+     *
+     * See {@code protected} methods for optional parameters you can override.
+     *
+     * @param context to be used for {@link Context#bindServiceAsUser binding} and
+     *                {@link Context#unbindService unbinding}
+     * @param userId  to be used for {@link Context#bindServiceAsUser binding}
+     */
+    RemoteOnDeviceTrustedInferenceService(Context context, ComponentName serviceName,
+            int userId) {
+        super(context, new Intent(
+                        OnDeviceTrustedInferenceService.SERVICE_INTERFACE).setComponent(serviceName),
+                BIND_FOREGROUND_SERVICE | BIND_INCLUDE_CAPABILITIES, userId,
+                IOnDeviceTrustedInferenceService.Stub::asInterface);
+
+        // Bind right away
+        connect();
+    }
+
+
+    @Override
+    protected long getAutoDisconnectTimeoutMs() {
+        // Disable automatic unbinding.
+        // TODO: add logic to fetch this flag via SecureSettings.
+        return -1;
+    }
+}
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index 133fc8f..59d3d17 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -143,7 +143,8 @@
     // Magic number to mark block device as adhering to the format consumed by this service
     private static final int PARTITION_TYPE_MARKER = 0x19901873;
     /** Size of the block reserved for FRP credential, including 4 bytes for the size header. */
-    private static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000;
+    @VisibleForTesting
+    static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000;
     /** Maximum size of the FRP credential handle that can be stored. */
     @VisibleForTesting
     static final int MAX_FRP_CREDENTIAL_HANDLE_SIZE = FRP_CREDENTIAL_RESERVED_SIZE - 4;
@@ -158,7 +159,8 @@
     /**
      * Size of the block reserved for Test Harness Mode data, including 4 bytes for the size header.
      */
-    private static final int TEST_MODE_RESERVED_SIZE = 10000;
+    @VisibleForTesting
+    static final int TEST_MODE_RESERVED_SIZE = 10000;
     /** Maximum size of the Test Harness Mode data that can be stored. */
     @VisibleForTesting
     static final int MAX_TEST_MODE_DATA_SIZE = TEST_MODE_RESERVED_SIZE - 4;
@@ -393,7 +395,8 @@
         return totalDataSize;
     }
 
-    private long getBlockDeviceSize() {
+    @VisibleForTesting
+    long getBlockDeviceSize() {
         synchronized (mLock) {
             if (mBlockDeviceSize == -1) {
                 if (mIsFileBacked) {
@@ -553,26 +556,33 @@
             channel.write(buf);
             channel.force(true);
 
-            // 3. skip the test mode data and leave it unformatted.
+            // 3. Write the default FRP secret (all zeros).
+            if (mFrpEnforced) {
+                Slog.i(TAG, "Writing FRP secret magic");
+                channel.write(ByteBuffer.wrap(FRP_SECRET_MAGIC));
+
+                Slog.i(TAG, "Writing default FRP secret");
+                channel.write(ByteBuffer.allocate(FRP_SECRET_SIZE));
+                channel.force(true);
+
+                mFrpActive = false;
+            }
+
+            // 4. skip the test mode data and leave it unformatted.
             //    This is for a feature that enables testing.
             channel.position(channel.position() + TEST_MODE_RESERVED_SIZE);
 
-            // 4. wipe the FRP_CREDENTIAL explicitly
+            // 5. wipe the FRP_CREDENTIAL explicitly
             buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
             channel.write(buf);
             channel.force(true);
 
-            // 5. set unlock = 0 because it's a formatPartitionLocked
+            // 6. set unlock = 0 because it's a formatPartitionLocked
             buf = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
             buf.put((byte)0);
             buf.flip();
             channel.write(buf);
             channel.force(true);
-
-            // 6. Write the default FRP secret (all zeros).
-            if (mFrpEnforced) {
-                writeFrpMagicAndDefaultSecret();
-            }
         } catch (IOException e) {
             Slog.e(TAG, "failed to format block", e);
             return;
@@ -616,7 +626,7 @@
             // version.  If so, we deactivate FRP and set the secret to the default value.
             if (isUpgradingFromPreVRelease()) {
                 Slog.w(TAG, "Upgrading from Android 14 or lower, defaulting FRP secret");
-                writeFrpMagicAndDefaultSecret();
+                writeFrpMagicAndDefaultSecretLocked();
                 mFrpActive = false;
                 return true;
             }
@@ -630,7 +640,7 @@
         try {
             return deactivateFrp(Files.readAllBytes(Paths.get(frpSecretFile)));
         } catch (IOException e) {
-            Slog.w(TAG, "Failed to read FRP secret file: " + frpSecretFile + " "
+            Slog.i(TAG, "Failed to read FRP secret file: " + frpSecretFile + " "
                     + e.getClass().getSimpleName());
             return false;
         }
@@ -653,7 +663,8 @@
     }
 
     /**
-     * Write the provided secret to the FRP secret file in /data and to the /persist partition.
+     * Write the provided secret to the FRP secret file in /data and to the persistent data block
+     * partition.
      *
      * Writing is a three-step process, to ensure that we can recover from a crash at any point.
      */
@@ -713,7 +724,7 @@
         synchronized (mLock) {
             if (!hasFrpSecretMagic()) {
                 Slog.i(TAG, "No FRP secret magic, system must have been upgraded.");
-                writeFrpMagicAndDefaultSecret();
+                writeFrpMagicAndDefaultSecretLocked();
             }
         }
 
@@ -735,11 +746,9 @@
         }
     }
 
-    private void writeFrpMagicAndDefaultSecret() {
+    private void writeFrpMagicAndDefaultSecretLocked() {
         try (FileChannel channel = getBlockOutputChannelIgnoringFrp()) {
             synchronized (mLock) {
-                // Write secret first in case we crash between the writes, causing the first write
-                // to be synced but the second to be lost.
                 Slog.i(TAG, "Writing default FRP secret");
                 channel.position(getFrpSecretDataOffset());
                 channel.write(ByteBuffer.allocate(FRP_SECRET_SIZE));
@@ -755,6 +764,7 @@
         } catch (IOException e) {
             Slog.e(TAG, "Failed to write FRP magic and default secret", e);
         }
+        computeAndWriteDigestLocked();
     }
 
     @VisibleForTesting
@@ -879,7 +889,7 @@
                 if (printSecret) {
                     try {
                         pw.println("FRP secret in " + frpSecretFile + ": " + HexFormat.of()
-                                .formatHex(Files.readAllBytes(Paths.get(mFrpSecretFile))));
+                                .formatHex(Files.readAllBytes(Paths.get(frpSecretFile))));
                     } catch (IOException e) {
                         Slog.e(TAG, "Failed to read " + frpSecretFile, e);
                     }
@@ -1230,6 +1240,7 @@
 
         @Override
         public boolean setFactoryResetProtectionSecret(byte[] secret) {
+            enforceConfigureFrpPermission();
             enforceUid(Binder.getCallingUid());
             if (secret == null || secret.length != FRP_SECRET_SIZE) {
                 throw new IllegalArgumentException(
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index e984e9c..23d48e8 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -45,6 +45,8 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
+import android.multiuser.Flags;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -361,14 +363,13 @@
         final UserInfo parent = ums.getProfileParent(userId);
         final int launcherUserId = (parent != null) ? parent.id : userId;
         final ComponentName launcherComponent = snapshot.getDefaultHomeActivity(launcherUserId);
-        if (launcherComponent != null) {
+        if (launcherComponent != null && canLauncherAccessProfile(launcherComponent, userId)) {
             Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
                     .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
                     .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
                     .setPackage(launcherComponent.getPackageName());
             mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUserId));
         }
-        // TODO(b/122900055) Change/Remove this and replace with new permission role.
         if (appPredictionServicePackage != null) {
             Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
                     .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
@@ -378,6 +379,36 @@
         }
     }
 
+    /**
+     * A Profile is accessible to launcher in question if:
+     * - It's not hidden for API visibility.
+     * - Hidden, but launcher application has either
+     *      {@link Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL} or
+     *      {@link Manifest.permission.ACCESS_HIDDEN_PROFILES}
+     *   granted.
+     */
+    boolean canLauncherAccessProfile(ComponentName launcherComponent, int userId) {
+        if (android.os.Flags.allowPrivateProfile()
+                && Flags.enablePermissionToAccessHiddenProfiles()) {
+            if (mUmInternal.getUserProperties(userId).getProfileApiVisibility()
+                    != UserProperties.PROFILE_API_VISIBILITY_HIDDEN) {
+                return true;
+            }
+            if (mContext.getPackageManager().checkPermission(
+                            Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL,
+                            launcherComponent.getPackageName())
+                    == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            }
+            // TODO(b/122900055) Change/Remove this and replace with new permission role.
+            return mContext.getPackageManager().checkPermission(
+                            Manifest.permission.ACCESS_HIDDEN_PROFILES,
+                            launcherComponent.getPackageName())
+                        == PackageManager.PERMISSION_GRANTED;
+        }
+        return true;
+    }
+
     void sendPreferredActivityChangedBroadcast(int userId) {
         mHandler.post(() -> {
             final IActivityManager am = ActivityManager.getService();
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f9d8112..76d87ff 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -798,6 +798,10 @@
         public ParceledListSlice getShortcutConfigActivities(
                 String callingPackage, String packageName, UserHandle user)
                 throws RemoteException {
+            // Not supported for user-profiles with items restricted on home screen.
+            if (!mShortcutServiceInternal.areShortcutsSupportedOnHomeScreen(user.getIdentifier())) {
+                return null;
+            }
             return queryActivitiesForUser(callingPackage,
                     new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user);
         }
@@ -1256,6 +1260,14 @@
         @Override
         public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
                 UserHandle targetUser) {
+            if (!mShortcutServiceInternal
+                    .areShortcutsSupportedOnHomeScreen(targetUser.getIdentifier())) {
+                // Requires strict ACCESS_SHORTCUTS permission for user-profiles with items
+                // restricted on home screen.
+                ensureStrictAccessShortcutsPermission(callingPackage);
+            } else {
+                ensureShortcutPermission(callingPackage);
+            }
             ensureShortcutPermission(callingPackage);
             if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) {
                 return;
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index dc97e5f..df4e5a3 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -122,6 +122,7 @@
 public class PackageArchiver {
 
     private static final String TAG = "PackageArchiverService";
+    private static final boolean DEBUG = true;
 
     public static final String EXTRA_UNARCHIVE_INTENT_SENDER =
             "android.content.pm.extra.UNARCHIVE_INTENT_SENDER";
@@ -203,6 +204,9 @@
         Objects.requireNonNull(intentSender);
         Objects.requireNonNull(userHandle);
 
+        Slog.i(TAG,
+                TextUtils.formatSimple("Requested archival of package %s for user %s.", packageName,
+                        userHandle.getIdentifier()));
         Computer snapshot = mPm.snapshotComputer();
         int binderUserId = userHandle.getIdentifier();
         int binderUid = Binder.getCallingUid();
@@ -227,7 +231,7 @@
                 archiveStateStored[i] = createAndStoreArchiveState(packageName, users[i]);
             }
         } catch (PackageManager.NameNotFoundException e) {
-            Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s",
+            Slog.e(TAG, TextUtils.formatSimple("Failed to archive %s with message %s",
                     packageName, e.getMessage()));
             throw new ParcelableException(e);
         }
@@ -247,7 +251,7 @@
                         binderPid)
         ).exceptionally(
                 e -> {
-                    Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s",
+                    Slog.e(TAG, TextUtils.formatSimple("Failed to archive %s with message %s",
                             packageName, e.getMessage()));
                     sendFailureStatus(intentSender, packageName, e.getMessage());
                     return null;
@@ -350,17 +354,18 @@
                 ps.setArchiveState(/* archiveState= */ null, userId);
             }
         }
-        mPm.mBackgroundHandler.post(
-                () -> {
-                    File iconsDir = getIconsDir(packageName, userId);
-                    if (!iconsDir.exists()) {
-                        return;
-                    }
-                    // TODO(b/319238030) Move this into installd.
-                    if (!FileUtils.deleteContentsAndDir(iconsDir)) {
-                        Slog.e(TAG, "Failed to clean up archive files for " + packageName);
-                    }
-                });
+        File iconsDir = getIconsDir(packageName, userId);
+        if (!iconsDir.exists()) {
+            return;
+        }
+        // TODO(b/319238030) Move this into installd.
+        if (!FileUtils.deleteContentsAndDir(iconsDir)) {
+            Slog.e(TAG, "Failed to clean up archive files for " + packageName);
+        } else {
+            if (DEBUG) {
+                Slog.e(TAG, "Deleted icons at " + iconsDir.getAbsolutePath());
+            }
+        }
     }
 
     @Nullable
@@ -521,6 +526,9 @@
             }
             out.flush();
         }
+        if (DEBUG && iconFile.exists()) {
+            Slog.i(TAG, "Stored icon at " + iconFile.getAbsolutePath());
+        }
         return iconFile.toPath();
     }
 
@@ -1191,6 +1199,9 @@
             if (!iconsDir.isDirectory()) {
                 throw new IOException("Unable to create directory " + iconsDir);
             }
+            if (DEBUG) {
+                Slog.i(TAG, "Created icons directory at " + iconsDir.getAbsolutePath());
+            }
         }
         SELinux.restorecon(iconsDir);
         return iconsDir;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6e4f199..29320ae 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1702,6 +1702,10 @@
         Objects.requireNonNull(installerPackageName);
         Objects.requireNonNull(userHandle);
 
+        Slog.i(TAG,
+                TextUtils.formatSimple("Requested archived install of package %s for user %s.",
+                        archivedPackageParcel.packageName,
+                        userHandle.getIdentifier()));
         final int callingUid = Binder.getCallingUid();
         final int userId = userHandle.getIdentifier();
         final Computer snapshot = mPm.snapshotComputer();
@@ -1737,6 +1741,8 @@
                 session.addFile(LOCATION_DATA_APP, "base", 0 /*lengthBytes*/,
                         metadata.toByteArray(), null /*signature*/);
                 session.commit(statusReceiver, false /*forTransfer*/);
+                Slog.i(TAG, TextUtils.formatSimple("Installed archived app %s.",
+                        archivedPackageParcel.packageName));
             } catch (IOException e) {
                 throw ExceptionUtils.wrap(e);
             } finally {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 29242aa..fe65010 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5358,9 +5358,16 @@
             pw.println(sdf.format(date));
 
             if (pus.getArchiveState() != null) {
+                final ArchiveState archiveState = pus.getArchiveState();
                 pw.print("      archiveTime=");
-                date.setTime(pus.getArchiveState().getArchiveTimeMillis());
+                date.setTime(archiveState.getArchiveTimeMillis());
                 pw.println(sdf.format(date));
+                pw.print("      unarchiveInstallerTitle=");
+                pw.println(archiveState.getInstallerTitle());
+                for (ArchiveState.ArchiveActivityInfo activity : archiveState.getActivityInfos()) {
+                    pw.print("        archiveActivityInfo=");
+                    pw.println(activity.toString());
+                }
             }
 
             pw.print("      uninstallReason=");
@@ -5475,10 +5482,6 @@
                     }
                 }
             }
-            ArchiveState archiveState = userState.getArchiveState();
-            if (archiveState != null) {
-                pw.print(archiveState.toString());
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index 1e1f178..47a140a 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -416,6 +416,10 @@
     @VisibleForTesting
     Pair<ComponentName, Integer> getRequestPinConfirmationActivity(
             int callingUserId, int requestType) {
+        // Pinning is not supported for user-profiles with items restricted on home screen.
+        if (!mService.areShortcutsSupportedOnHomeScreen(callingUserId)) {
+            return null;
+        }
         // Find the default launcher.
         final int launcherUserId = mService.getParentOrSelfUserId(callingUserId);
         final String defaultLauncher = mService.getDefaultLauncher(launcherUserId);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c23d2ab..a600eea 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -70,6 +70,7 @@
 import android.graphics.RectF;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Icon;
+import android.multiuser.Flags;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -2830,6 +2831,26 @@
         }
     }
 
+    @VisibleForTesting
+    boolean areShortcutsSupportedOnHomeScreen(@UserIdInt int userId) {
+        if (!android.os.Flags.allowPrivateProfile() || !Flags.disablePrivateSpaceItemsOnHome()) {
+            return true;
+        }
+        final long start = getStatStartTime();
+        final long token = injectClearCallingIdentity();
+        boolean isSupported;
+        try {
+            synchronized (mLock) {
+                isSupported = !mUserManagerInternal.getUserProperties(userId)
+                        .areItemsRestrictedOnHomeScreen();
+            }
+        } finally {
+            injectRestoreCallingIdentity(token);
+            logDurationStat(Stats.GET_DEFAULT_LAUNCHER, start);
+        }
+        return isSupported;
+    }
+
     @Nullable
     String getDefaultLauncher(@UserIdInt int userId) {
         final long start = getStatStartTime();
@@ -3660,6 +3681,10 @@
                     callingPid, callingUid);
         }
 
+        public boolean areShortcutsSupportedOnHomeScreen(@UserIdInt int userId) {
+            return ShortcutService.this.areShortcutsSupportedOnHomeScreen(userId);
+        }
+
         @Override
         public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
                 int userId) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index a4c6959..3c6baa8 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -255,4 +255,9 @@
      * @param tile the ComponentName of the {@link android.service.quicksettings.TileService}
      */
     void removeQsTile(ComponentName tile);
+
+    /**
+     * Called when requested to enter desktop from an app.
+     */
+    void enterDesktop(int displayId);
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index fd316ea..14c38bd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -830,6 +830,15 @@
         }
 
         @Override
+        public void enterDesktop(int displayId) {
+            IStatusBar bar = mBar;
+            if (bar != null) {
+                try {
+                    bar.enterDesktop(displayId);
+                } catch (RemoteException ex) { }
+            }
+        }
+        @Override
         public void showMediaOutputSwitcher(String packageName) {
             IStatusBar bar = mBar;
             if (bar != null) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index fab0430..99ce3e2 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.SynchronousUserSwitchObserver;
 import android.app.UidObserver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -145,8 +146,6 @@
                     PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
                     PowerManager.GO_TO_SLEEP_REASON_TIMEOUT));
 
-    private static final IntentFilter USER_SWITCHED_INTENT_FILTER =
-            new IntentFilter(Intent.ACTION_USER_SWITCHED);
     private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER =
             new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
 
@@ -162,9 +161,11 @@
     @VisibleForTesting
     final SettingsContentObserver mSettingObserver;
     @VisibleForTesting
-    final MyUidObserver mUidObserver;
-    @VisibleForTesting
     final SettingsBroadcastReceiver mSettingChangeReceiver;
+    @VisibleForTesting
+    final VibrationUidObserver mUidObserver;
+    @VisibleForTesting
+    final VibrationUserSwitchObserver mUserSwitchObserver;
 
     @GuardedBy("mLock")
     private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
@@ -205,8 +206,9 @@
         mContext = context;
         mVibrationConfig = config;
         mSettingObserver = new SettingsContentObserver(handler);
-        mUidObserver = new MyUidObserver();
         mSettingChangeReceiver = new SettingsBroadcastReceiver();
+        mUidObserver = new VibrationUidObserver();
+        mUserSwitchObserver = new VibrationUserSwitchObserver();
         mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
                 .getSystemUiServiceComponent().getPackageName();
 
@@ -245,7 +247,13 @@
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
-                    ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                    ActivityManager.PROCESS_STATE_UNKNOWN, /* callingPackage= */ null);
+        } catch (RemoteException e) {
+            // ignored; both services live in system_server
+        }
+
+        try {
+            ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
@@ -270,7 +278,6 @@
                     }
                 });
 
-        registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
         registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
 
         // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity.
@@ -540,41 +547,44 @@
 
     /** Update all cached settings and triggers registered listeners. */
     void update() {
-        updateSettings();
+        updateSettings(UserHandle.USER_CURRENT);
         updateRingerMode();
         notifyListeners();
     }
 
-    private void updateSettings() {
+    private void updateSettings(int userHandle) {
         synchronized (mLock) {
-            mVibrateInputDevices = loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
-            mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1) > 0;
+            mVibrateInputDevices =
+                    loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0, userHandle) > 0;
+            mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1, userHandle) > 0;
             mKeyboardVibrationOn = loadSystemSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED,
-                    mVibrationConfig.isDefaultKeyboardVibrationEnabled() ? 1 : 0) > 0;
+                    mVibrationConfig.isDefaultKeyboardVibrationEnabled() ? 1 : 0, userHandle) > 0;
 
             int alarmIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_ALARM));
             int defaultHapticFeedbackIntensity = getDefaultIntensity(USAGE_TOUCH);
             int hapticFeedbackIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, -1, userHandle),
                     defaultHapticFeedbackIntensity);
             int positiveHapticFeedbackIntensity = toPositiveIntensity(
                     hapticFeedbackIntensity, defaultHapticFeedbackIntensity);
             int hardwareFeedbackIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, -1,
+                            userHandle),
                     positiveHapticFeedbackIntensity);
             int mediaIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_MEDIA));
             int defaultNotificationIntensity = getDefaultIntensity(USAGE_NOTIFICATION);
             int notificationIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, -1,
+                            userHandle),
                     defaultNotificationIntensity);
             int positiveNotificationIntensity = toPositiveIntensity(
                     notificationIntensity, defaultNotificationIntensity);
             int ringIntensity = toIntensity(
-                    loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1),
+                    loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_RINGTONE));
 
             mCurrentVibrationIntensities.clear();
@@ -593,7 +603,7 @@
             mCurrentVibrationIntensities.put(USAGE_HARDWARE_FEEDBACK, hardwareFeedbackIntensity);
             mCurrentVibrationIntensities.put(USAGE_PHYSICAL_EMULATION, hardwareFeedbackIntensity);
 
-            if (!loadBooleanSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED)) {
+            if (!loadBooleanSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, userHandle)) {
                 // Make sure deprecated boolean setting still disables touch vibrations.
                 mCurrentVibrationIntensities.put(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_OFF);
             } else {
@@ -744,14 +754,13 @@
         return value;
     }
 
-    private boolean loadBooleanSetting(String settingKey) {
-        return Settings.System.getIntForUser(mContext.getContentResolver(),
-                settingKey, 0, UserHandle.USER_CURRENT) != 0;
+    private boolean loadBooleanSetting(String settingKey, int userHandle) {
+        return loadSystemSetting(settingKey, 0, userHandle) != 0;
     }
 
-    private int loadSystemSetting(String settingName, int defaultValue) {
+    private int loadSystemSetting(String settingName, int defaultValue, int userHandle) {
         return Settings.System.getIntForUser(mContext.getContentResolver(),
-                settingName, defaultValue, UserHandle.USER_CURRENT);
+                settingName, defaultValue, userHandle);
     }
 
     private void registerSettingsObserver(Uri settingUri) {
@@ -828,24 +837,18 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            updateSettings();
+            updateSettings(UserHandle.USER_CURRENT);
             notifyListeners();
         }
     }
 
-    /**
-     * Implementation of {@link BroadcastReceiver} to update settings on current user or ringer
-     * mode change.
-     */
+    /** Implementation of {@link BroadcastReceiver} to update on ringer mode change. */
     @VisibleForTesting
     final class SettingsBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                // Reload all settings, as they are user-based.
-                update();
-            } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
+            if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
                 updateRingerMode();
                 notifyListeners();
             }
@@ -854,7 +857,7 @@
 
     /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
     @VisibleForTesting
-    final class MyUidObserver extends UidObserver {
+    final class VibrationUidObserver extends UidObserver {
         private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
 
         public boolean isUidForeground(int uid) {
@@ -878,4 +881,23 @@
             }
         }
     }
+
+    /** Implementation of {@link SynchronousUserSwitchObserver} to update on user switch. */
+    @VisibleForTesting
+    final class VibrationUserSwitchObserver extends SynchronousUserSwitchObserver {
+
+        @Override
+        public void onUserSwitching(int newUserId) {
+            // Reload settings early based on new user id.
+            updateSettings(newUserId);
+            notifyListeners();
+        }
+
+        @Override
+        public void onUserSwitchComplete(int newUserId) {
+            // Reload all settings including ones from AudioManager,
+            // as they are based on UserHandle.USER_CURRENT.
+            update();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 759450b..5d172a9 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -2220,9 +2220,12 @@
             // only cancel background vibrations.
             IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
                     : mShellCallbacksToken;
-            HalVibration vib = vibrateWithPermissionCheck(Binder.getCallingUid(),
-                    Context.DEVICE_ID_DEFAULT, SHELL_PACKAGE_NAME, combined, attrs,
-                    commonOptions.description, deathBinder);
+            int uid = Binder.getCallingUid();
+            // Resolve the package name for the client based on the process UID, to cover cases like
+            // rooted shell clients using ROOT_UID.
+            String resolvedPackageName = AppOpsManager.resolvePackageName(uid, SHELL_PACKAGE_NAME);
+            HalVibration vib = vibrateWithPermissionCheck(uid, Context.DEVICE_ID_DEFAULT,
+                    resolvedPackageName, combined, attrs, commonOptions.description, deathBinder);
             maybeWaitOnVibration(vib, commonOptions);
         }
 
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index ea8a801..3b2e69a 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -39,11 +40,14 @@
 import android.webkit.WebViewZygote;
 
 import com.android.internal.util.XmlUtils;
+import com.android.server.LocalServices;
+import com.android.server.PinnerService;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -60,6 +64,7 @@
     private static final String TAG_AVAILABILITY = "availableByDefault";
     private static final String TAG_SIGNATURE = "signature";
     private static final String TAG_FALLBACK = "isFallback";
+    private static final String PIN_GROUP = "webview";
     private final WebViewProviderInfo[] mWebViewProviderPackages;
 
     // Initialization-on-demand holder idiom for getting the WebView provider packages once and
@@ -277,6 +282,36 @@
         return true;
     }
 
+    @Override
+    public void pinWebviewIfRequired(ApplicationInfo appInfo) {
+        PinnerService pinnerService = LocalServices.getService(PinnerService.class);
+        int webviewPinQuota = pinnerService.getWebviewPinQuota();
+        if (webviewPinQuota <= 0) {
+            return;
+        }
+
+        pinnerService.unpinGroup(PIN_GROUP);
+
+        ArrayList<String> apksToPin = new ArrayList<>();
+        boolean pinSharedFirst = appInfo.metaData.getBoolean("PIN_SHARED_LIBS_FIRST", true);
+        for (String sharedLib : appInfo.sharedLibraryFiles) {
+            apksToPin.add(sharedLib);
+        }
+        apksToPin.add(appInfo.sourceDir);
+        if (!pinSharedFirst) {
+            // We want to prioritize pinning of the native library that is most likely used by apps
+            // which in some build flavors live in the main apk and as a shared library for others.
+            Collections.reverse(apksToPin);
+        }
+        for (String apk : apksToPin) {
+            if (webviewPinQuota <= 0) {
+                break;
+            }
+            int bytesPinned = pinnerService.pinFile(apk, webviewPinQuota, appInfo, PIN_GROUP);
+            webviewPinQuota -= bytesPinned;
+        }
+    }
+
     // flags declaring we want extra info from the package manager for webview providers
     private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
             | PackageManager.GET_SIGNATURES | PackageManager.GET_SHARED_LIBRARY_FILES
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index 09c23a7..5ed2cfe 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -17,6 +17,7 @@
 package com.android.server.webkit;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.webkit.UserPackage;
@@ -61,4 +62,6 @@
     /** Start the zygote if it's not already running. */
     public void ensureZygoteStarted();
     public boolean isMultiProcessDefaultEnabled();
+
+    public void pinWebviewIfRequired(ApplicationInfo appInfo);
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index d95b431..1d6ad6d 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -17,7 +17,6 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
@@ -30,12 +29,8 @@
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewProviderResponse;
 
-import com.android.server.LocalServices;
-import com.android.server.PinnerService;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -93,8 +88,6 @@
     private static final int MULTIPROCESS_SETTING_ON_VALUE = Integer.MAX_VALUE;
     private static final int MULTIPROCESS_SETTING_OFF_VALUE = Integer.MIN_VALUE;
 
-    private static final String PIN_GROUP = "webview";
-
     private final SystemInterface mSystemInterface;
     private final Context mContext;
 
@@ -346,38 +339,6 @@
         return newPackage;
     }
 
-    private void pinWebviewIfRequired(ApplicationInfo appInfo) {
-        PinnerService pinnerService = LocalServices.getService(PinnerService.class);
-        if (pinnerService == null) {
-            // This happens in unit tests which do not have services.
-            return;
-        }
-        int webviewPinQuota = pinnerService.getWebviewPinQuota();
-        if (webviewPinQuota <= 0) {
-            return;
-        }
-
-        pinnerService.unpinGroup(PIN_GROUP);
-
-        ArrayList<String> apksToPin = new ArrayList<>();
-        boolean pinSharedFirst = appInfo.metaData.getBoolean("PIN_SHARED_LIBS_FIRST", true);
-        for (String sharedLib : appInfo.sharedLibraryFiles) {
-            apksToPin.add(sharedLib);
-        }
-        apksToPin.add(appInfo.sourceDir);
-        if (!pinSharedFirst) {
-            // We want to prioritize pinning of the native library that is most likely used by apps
-            // which in some build flavors live in the main apk and as a shared library for others.
-            Collections.reverse(apksToPin);
-        }
-        for (String apk : apksToPin) {
-            if (webviewPinQuota <= 0) {
-                break;
-            }
-            int bytesPinned = pinnerService.pinFile(apk, webviewPinQuota, appInfo, PIN_GROUP);
-            webviewPinQuota -= bytesPinned;
-        }
-    }
     /**
      * This is called when we change WebView provider, either when the current provider is
      * updated or a new provider is chosen / takes precedence.
@@ -386,7 +347,7 @@
         synchronized (mLock) {
             mAnyWebViewInstalled = true;
             if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
-                pinWebviewIfRequired(newPackage.applicationInfo);
+                mSystemInterface.pinWebviewIfRequired(newPackage.applicationInfo);
                 mCurrentWebViewPackage = newPackage;
 
                 // The relro creations might 'finish' (not start at all) before
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index 1bc635b..b3c8b0b 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -17,7 +17,6 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
@@ -32,12 +31,8 @@
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewProviderResponse;
 
-import com.android.server.LocalServices;
-import com.android.server.PinnerService;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -88,10 +83,9 @@
     private static final int VALIDITY_INCORRECT_SIGNATURE = 3;
     private static final int VALIDITY_NO_LIBRARY_FLAG = 4;
 
-    private static final String PIN_GROUP = "webview";
-
     private final SystemInterface mSystemInterface;
     private final Context mContext;
+    private final WebViewProviderInfo mDefaultProvider;
 
     private long mMinimumVersionCode = -1;
 
@@ -112,6 +106,16 @@
     WebViewUpdateServiceImpl2(Context context, SystemInterface systemInterface) {
         mContext = context;
         mSystemInterface = systemInterface;
+        WebViewProviderInfo[] webviewProviders = getWebViewPackages();
+        for (WebViewProviderInfo provider : webviewProviders) {
+            if (provider.availableByDefault) {
+                mDefaultProvider = provider;
+                break;
+            }
+        }
+        // This should be unreachable because the config parser enforces that there is at least one
+        // availableByDefault provider.
+        throw new AndroidRuntimeException("No available by default WebView Provider.");
     }
 
     @Override
@@ -170,11 +174,10 @@
         if (mCurrentWebViewPackage == null) {
             return true;
         }
-        WebViewProviderInfo defaultProvider = getDefaultWebViewPackage();
-        if (mCurrentWebViewPackage.packageName.equals(defaultProvider.packageName)) {
+        if (mCurrentWebViewPackage.packageName.equals(mDefaultProvider.packageName)) {
             List<UserPackage> userPackages =
                     mSystemInterface.getPackageInfoForProviderAllUsers(
-                            mContext, defaultProvider);
+                            mContext, mDefaultProvider);
             return !isInstalledAndEnabledForAllUsers(userPackages);
         } else {
             return false;
@@ -207,13 +210,12 @@
                 // default package for all users in case it was disabled, even if we already did the
                 // one-time migration before. If this actually changes the state, we will see the
                 // PackageManager broadcast shortly and try again.
-                WebViewProviderInfo defaultProvider = getDefaultWebViewPackage();
                 Slog.w(
                         TAG,
                         "No provider available for all users, trying to enable "
-                                + defaultProvider.packageName);
+                                + mDefaultProvider.packageName);
                 mSystemInterface.enablePackageForAllUsers(
-                        mContext, defaultProvider.packageName, true);
+                        mContext, mDefaultProvider.packageName, true);
             }
 
         } catch (Throwable t) {
@@ -356,39 +358,6 @@
         return newPackage;
     }
 
-    private void pinWebviewIfRequired(ApplicationInfo appInfo) {
-        PinnerService pinnerService = LocalServices.getService(PinnerService.class);
-        if (pinnerService == null) {
-            // This happens in unit tests which do not have services.
-            return;
-        }
-        int webviewPinQuota = pinnerService.getWebviewPinQuota();
-        if (webviewPinQuota <= 0) {
-            return;
-        }
-
-        pinnerService.unpinGroup(PIN_GROUP);
-
-        ArrayList<String> apksToPin = new ArrayList<>();
-        boolean pinSharedFirst = appInfo.metaData.getBoolean("PIN_SHARED_LIBS_FIRST", true);
-        for (String sharedLib : appInfo.sharedLibraryFiles) {
-            apksToPin.add(sharedLib);
-        }
-        apksToPin.add(appInfo.sourceDir);
-        if (!pinSharedFirst) {
-            // We want to prioritize pinning of the native library that is most likely used by apps
-            // which in some build flavors live in the main apk and as a shared library for others.
-            Collections.reverse(apksToPin);
-        }
-        for (String apk : apksToPin) {
-            if (webviewPinQuota <= 0) {
-                break;
-            }
-            int bytesPinned = pinnerService.pinFile(apk, webviewPinQuota, appInfo, PIN_GROUP);
-            webviewPinQuota -= bytesPinned;
-        }
-    }
-
     /**
      * This is called when we change WebView provider, either when the current provider is
      * updated or a new provider is chosen / takes precedence.
@@ -397,7 +366,7 @@
         synchronized (mLock) {
             mAnyWebViewInstalled = true;
             if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
-                pinWebviewIfRequired(newPackage.applicationInfo);
+                mSystemInterface.pinWebviewIfRequired(newPackage.applicationInfo);
                 mCurrentWebViewPackage = newPackage;
 
                 // The relro creations might 'finish' (not start at all) before
@@ -438,15 +407,7 @@
      */
     @Override
     public WebViewProviderInfo getDefaultWebViewPackage() {
-        WebViewProviderInfo[] webviewProviders = getWebViewPackages();
-        for (WebViewProviderInfo provider : webviewProviders) {
-            if (provider.availableByDefault) {
-                return provider;
-            }
-        }
-        // This should be unreachable because the config parser enforces that there is at least one
-        // availableByDefault provider.
-        throw new AndroidRuntimeException("No available by default WebView Provider.");
+        return mDefaultProvider;
     }
 
     private static class ProviderAndPackageInfo {
@@ -507,14 +468,13 @@
 
         // User did not choose, or the choice failed; return the default provider even if it is not
         // installed or enabled for all users.
-        WebViewProviderInfo defaultProvider = getDefaultWebViewPackage();
         try {
-            PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(defaultProvider);
-            if (validityResult(defaultProvider, packageInfo) == VALIDITY_OK) {
+            PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(mDefaultProvider);
+            if (validityResult(mDefaultProvider, packageInfo) == VALIDITY_OK) {
                 return packageInfo;
             }
         } catch (NameNotFoundException e) {
-            Slog.w(TAG, "Default WebView package (" + defaultProvider.packageName + ") not found");
+            Slog.w(TAG, "Default WebView package (" + mDefaultProvider.packageName + ") not found");
         }
 
         // This should never happen during normal operation (only with modified system images).
diff --git a/services/core/java/com/android/server/wm/ActivityCallerState.java b/services/core/java/com/android/server/wm/ActivityCallerState.java
index e797290..fa0b176 100644
--- a/services/core/java/com/android/server/wm/ActivityCallerState.java
+++ b/services/core/java/com/android/server/wm/ActivityCallerState.java
@@ -30,6 +30,7 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.BadParcelableException;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.util.ArraySet;
@@ -43,6 +44,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.WeakHashMap;
 
 /**
@@ -143,8 +145,8 @@
         final boolean writeMet = callerInfo.mWritableContentUris.contains(grantUri);
 
         if (!readMet && !writeMet) {
-            throw new IllegalArgumentException("The supplied URI wasn't passed at launch: "
-                    + grantUri.uri.toSafeString());
+            throw new IllegalArgumentException("The supplied URI wasn't passed at launch in"
+                    + " #getData, #EXTRA_STREAM, nor #getClipData: " + grantUri.uri.toSafeString());
         }
 
         final boolean checkRead = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0;
@@ -184,6 +186,18 @@
         // getData
         addUriIfContentUri(intent.getData(), uris);
 
+        // EXTRA_STREAM
+        if (intent.hasExtra(Intent.EXTRA_STREAM)) {
+            final ArrayList<Uri> streams = tryToUnparcelArrayListExtraStreamsUri(intent);
+            if (streams == null) {
+                addUriIfContentUri(tryToUnparcelExtraStreamUri(intent), uris);
+            } else {
+                for (int i = streams.size() - 1; i >= 0; i--) {
+                    addUriIfContentUri(streams.get(i), uris);
+                }
+            }
+        }
+
         final ClipData clipData = intent.getClipData();
         if (clipData == null) return uris;
 
@@ -199,6 +213,33 @@
         return uris;
     }
 
+    private static Uri tryToUnparcelExtraStreamUri(Intent intent) {
+        try {
+            return intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);
+        } catch (BadParcelableException e) {
+            // Even though the system "defuses" all the parsed Bundles, i.e. suppresses and logs
+            // instances of {@link BadParcelableException}, we still want to be on the safer side
+            // and catch the exception to ensure no breakages happen. If the unparcel fails, the
+            // item is still preserved with the underlying parcel.
+            Slog.w(TAG, "Failed to unparcel an URI in EXTRA_STREAM, returning null: " + e);
+            return null;
+        }
+    }
+
+    private static ArrayList<Uri> tryToUnparcelArrayListExtraStreamsUri(Intent intent) {
+        try {
+            return intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri.class);
+        } catch (BadParcelableException e) {
+            // Even though the system "defuses" all the parsed Bundles, i.e. suppresses and logs
+            // instances of {@link BadParcelableException}, we still want to be on the safer side
+            // and catch the exception to ensure no breakages happen. If the unparcel fails, the
+            // item is still preserved with the underlying parcel.
+            Slog.w(TAG, "Failed to unparcel an ArrayList of URIs in EXTRA_STREAM, returning null: "
+                    + e);
+            return null;
+        }
+    }
+
     private static void addUriIfContentUri(Uri uri, ArraySet<Uri> uris) {
         if (uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
             uris.add(uri);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c36df8d..2696fb6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1846,20 +1846,20 @@
         mLetterboxUiController.onMovedToDisplay(mDisplayContent.getDisplayId());
     }
 
-    void layoutLetterbox(WindowState winHint) {
-        mLetterboxUiController.layoutLetterbox(winHint);
+    void layoutLetterboxIfNeeded(WindowState winHint) {
+        mLetterboxUiController.layoutLetterboxIfNeeded(winHint);
     }
 
     boolean hasWallpaperBackgroundForLetterbox() {
         return mLetterboxUiController.hasWallpaperBackgroundForLetterbox();
     }
 
-    void updateLetterboxSurface(WindowState winHint, Transaction t) {
-        mLetterboxUiController.updateLetterboxSurface(winHint, t);
+    void updateLetterboxSurfaceIfNeeded(WindowState winHint, Transaction t) {
+        mLetterboxUiController.updateLetterboxSurfaceIfNeeded(winHint, t);
     }
 
-    void updateLetterboxSurface(WindowState winHint) {
-        mLetterboxUiController.updateLetterboxSurface(winHint);
+    void updateLetterboxSurfaceIfNeeded(WindowState winHint) {
+        mLetterboxUiController.updateLetterboxSurfaceIfNeeded(winHint);
     }
 
     /** Gets the letterbox insets. The insets will be empty if there is no letterbox. */
@@ -4546,7 +4546,7 @@
         }
         super.removeChild(child);
         checkKeyguardFlagsChanged();
-        updateLetterboxSurface(child);
+        updateLetterboxSurfaceIfNeeded(child);
     }
 
     void setAppLayoutChanges(int changes, String reason) {
@@ -6036,7 +6036,7 @@
         if (destroyedSomething) {
             final DisplayContent dc = getDisplayContent();
             dc.assignWindowLayers(true /*setLayoutNeeded*/);
-            updateLetterboxSurface(null);
+            updateLetterboxSurfaceIfNeeded(null);
         }
     }
 
@@ -7688,7 +7688,7 @@
         }
 
         if (mNeedsLetterboxedAnimation) {
-            updateLetterboxSurface(findMainWindow(), t);
+            updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
             mNeedsAnimationBoundsLayer = true;
         }
 
@@ -7856,7 +7856,7 @@
         mNeedsAnimationBoundsLayer = false;
         if (mNeedsLetterboxedAnimation) {
             mNeedsLetterboxedAnimation = false;
-            updateLetterboxSurface(findMainWindow(), t);
+            updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
         }
 
         if (mAnimatingActivityRegistry != null) {
@@ -8943,6 +8943,15 @@
             }
         }
 
+        // Fixed orientation bounds are the same as its parent container, so clear the fixed
+        // orientation bounds. This can happen in close to square displays where the orientation
+        // is not respected with insets, but the display still matches or is less than the
+        // activity aspect ratio.
+        if (resolvedBounds.equals(parentBounds)) {
+            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}.
         getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 2c49203..533529a 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -639,6 +639,10 @@
         return mPendingRemoteAnimationRegistry;
     }
 
+    ActivityRecord getLastStartActivity() {
+        return mLastStarter != null ? mLastStarter.mStartActivity : null;
+    }
+
     void dumpLastHomeActivityStartResult(PrintWriter pw, String prefix) {
         pw.print(prefix);
         pw.print("mLastHomeActivityStartResult=");
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3637ab1..adbe800 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5554,7 +5554,7 @@
      * Saves the current activity manager state and includes the saved state in the next dump of
      * activity manager.
      */
-    void saveANRState(String reason) {
+    void saveANRState(ActivityRecord activity, String reason) {
         final StringWriter sw = new StringWriter();
         final PrintWriter pw = new FastPrintWriter(sw, false, 1024);
         pw.println("  ANR time: " + DateFormat.getDateTimeInstance().format(new Date()));
@@ -5562,14 +5562,25 @@
             pw.println("  Reason: " + reason);
         }
         pw.println();
-        getActivityStartController().dump(pw, "  ", null);
-        pw.println();
+        if (activity != null) {
+            final Task rootTask = activity.getRootTask();
+            if (rootTask != null) {
+                rootTask.forAllTaskFragments(
+                        tf -> tf.dumpInner("  ", pw, true /* dumpAll */, null /* dumpPackage */));
+                pw.println();
+            }
+            mActivityStartController.dump(pw, "  ", activity.packageName);
+            if (mActivityStartController.getLastStartActivity() != activity) {
+                activity.dump(pw, "  ", true /* dumpAll */);
+            }
+        }
+        ActivityTaskSupervisor.printThisActivity(pw, mRootWindowContainer.getTopResumedActivity(),
+                null /* dumpPackage */, INVALID_DISPLAY, true /* needSep */,
+                "  ResumedActivity: ", /* header= */ null /* header */);
+        mLockTaskController.dump(pw, "  ");
+        mKeyguardController.dump(pw, "  ");
         pw.println("-------------------------------------------------------------------"
                 + "------------");
-        dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
-                true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
-                INVALID_DISPLAY, "" /* header */);
-        pw.println();
         pw.close();
 
         mLastANRState = sw.toString();
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index b9f6e17..0013c5c 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -367,7 +367,7 @@
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "dumpAnrStateLocked()");
                 synchronized (mService.mGlobalLock) {
                     mService.saveANRStateLocked(activity, windowState, reason);
-                    mService.mAtmService.saveANRState(reason);
+                    mService.mAtmService.saveANRState(activity, reason);
                 }
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c2dfa21..38ee456 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -629,7 +629,7 @@
                 final ActivityRecord ar = openApps.valueAt(i);
                 if (mAnimationHandler.isTarget(ar, true /* open */)) {
                     openApps.removeAt(i);
-                    mAnimationHandler.markStartingSurfaceMatch();
+                    mAnimationHandler.markStartingSurfaceMatch(null /* reparentTransaction */);
                 }
             }
             for (int i = closeApps.size() - 1; i >= 0; --i) {
@@ -773,10 +773,15 @@
             for (int i = mTmpOpenApps.size() - 1; i >= 0; --i) {
                 final WindowContainer wc = mTmpOpenApps.get(i);
                 if (mAnimationHandler.isTarget(wc, true /* open */)) {
-                    mAnimationHandler.markStartingSurfaceMatch();
+                    mAnimationHandler.markStartingSurfaceMatch(startTransaction);
                     break;
                 }
             }
+            // release animation leash
+            if (mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction != null) {
+                startTransaction.merge(mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction);
+                mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction = null;
+            }
             // Because the target will reparent to transition root, so it cannot be controlled by
             // animation leash. Hide the close target when transition starts.
             startTransaction.hide(mAnimationHandler.mCloseAdaptor.mTarget.getSurfaceControl());
@@ -993,7 +998,7 @@
             }
             final RemoteAnimationTarget[] targets = new RemoteAnimationTarget[2];
             targets[0] = mCloseAdaptor.mAnimationTarget;
-            targets[1] = mOpenAnimAdaptor.getOrCreateAnimationTarget();
+            targets[1] = mOpenAnimAdaptor.mRemoteAnimationTarget;
             return targets;
         }
 
@@ -1067,11 +1072,12 @@
             }
         }
 
-        void markStartingSurfaceMatch() {
-            mStartingSurfaceTargetMatch = true;
-            for (int i = mOpenAnimAdaptor.mAdaptors.length - 1; i >= 0; --i) {
-                mOpenAnimAdaptor.mAdaptors[i].reparentWindowlessSurfaceToTarget();
+        void markStartingSurfaceMatch(SurfaceControl.Transaction reparentTransaction) {
+            if (mStartingSurfaceTargetMatch) {
+                return;
             }
+            mStartingSurfaceTargetMatch = true;
+            mOpenAnimAdaptor.reparentWindowlessSurfaceToTarget(reparentTransaction);
         }
 
         void clearBackAnimateTarget() {
@@ -1140,14 +1146,23 @@
 
         private static class BackWindowAnimationAdaptorWrapper {
             final BackWindowAnimationAdaptor[] mAdaptors;
+            // The highest remote animation target, which can be a wrapper if multiple adaptors,
+            // or the single opening target.
+            final RemoteAnimationTarget mRemoteAnimationTarget;
             SurfaceControl.Transaction mCloseTransaction;
 
+            // The starting surface task Id. Used to clear the starting surface if the animation has
+            // requested one during animating.
+            private int mRequestedStartingSurfaceId = INVALID_TASK_ID;
+            private SurfaceControl mStartingSurface;
             BackWindowAnimationAdaptorWrapper(boolean isOpen, int switchType,
                     @NonNull WindowContainer... targets) {
                 mAdaptors = new BackWindowAnimationAdaptor[targets.length];
                 for (int i = targets.length - 1; i >= 0; --i) {
                     mAdaptors[i] = createAdaptor(targets[i], isOpen, switchType);
                 }
+                mRemoteAnimationTarget = targets.length > 1 ? createWrapTarget()
+                        : mAdaptors[0].mAnimationTarget;
             }
 
             boolean isValid() {
@@ -1160,75 +1175,151 @@
             }
 
             void cleanUp(boolean startingSurfaceMatch) {
+                cleanUpWindowlessSurface(startingSurfaceMatch);
                 for (int i = mAdaptors.length - 1; i >= 0; --i) {
-                    mAdaptors[i].cleanUpWindowlessSurface(startingSurfaceMatch);
                     mAdaptors[i].mTarget.cancelAnimation();
                 }
+                mRequestedStartingSurfaceId = INVALID_TASK_ID;
+                mStartingSurface = null;
                 if (mCloseTransaction != null) {
                     mCloseTransaction.apply();
                     mCloseTransaction = null;
                 }
             }
 
-            void onAnimationFinish() {
-                final SurfaceControl.Transaction pt = mAdaptors[0].mTarget.getPendingTransaction();
-                if (mCloseTransaction != null) {
-                    pt.merge(mCloseTransaction);
-                    mCloseTransaction = null;
-                }
-                if (mAdaptors.length > 1) {
-                    for (int i = mAdaptors.length - 1; i >= 0; --i) {
-                        final WindowContainer wc = mAdaptors[i].mTarget;
-                        final WindowContainer parent = wc.getParent();
-                        if (parent != null) {
-                            pt.reparent(wc.getSurfaceControl(),
-                                    parent.getSurfaceControl());
-                        }
-                    }
-                }
-            }
-
-            @NonNull RemoteAnimationTarget getOrCreateAnimationTarget() {
+            private RemoteAnimationTarget createWrapTarget() {
                 // Special handle for opening two activities together.
                 // If we animate both activities separately, the animation area and rounded corner
                 // would also being handled separately. To make them seem like "open" together, wrap
                 // their leash with another animation leash.
-                if (mAdaptors.length > 1 && mCloseTransaction == null) {
-                    final Rect unionBounds = new Rect();
-                    for (int i = mAdaptors.length - 1; i >= 0; --i) {
-                        unionBounds.union(mAdaptors[i].mAnimationTarget.localBounds);
-                    }
-                    final WindowContainer wc = mAdaptors[0].mTarget;
-                    final Task task = wc.asActivityRecord() != null
-                            ? wc.asActivityRecord().getTask() : wc.asTask();
-                    final RemoteAnimationTarget represent = mAdaptors[0].mAnimationTarget;
-                    final SurfaceControl leashSurface = new SurfaceControl.Builder()
-                            .setName("cross-animation-leash")
-                            .setContainerLayer()
-                            .setHidden(false)
-                            .setParent(task.getSurfaceControl())
-                            .build();
-                    final SurfaceControl.Transaction pt = wc.getPendingTransaction();
-                    pt.setLayer(leashSurface, wc.getParent().getLastLayer());
-                    mCloseTransaction = new SurfaceControl.Transaction();
-                    mCloseTransaction.reparent(leashSurface, null);
-                    for (int i = mAdaptors.length - 1; i >= 0; --i) {
-                        BackWindowAnimationAdaptor adaptor = mAdaptors[i];
-                        pt.reparent(adaptor.mAnimationTarget.leash, leashSurface);
-                        pt.setPosition(adaptor.mAnimationTarget.leash,
-                                adaptor.mAnimationTarget.localBounds.left,
-                                adaptor.mAnimationTarget.localBounds.top);
-                    }
-                    return new RemoteAnimationTarget(represent.taskId, represent.mode, leashSurface,
-                            represent.isTranslucent, represent.clipRect, represent.contentInsets,
-                            represent.prefixOrderIndex,
-                            new Point(unionBounds.left, unionBounds.top),
-                            unionBounds, unionBounds, represent.windowConfiguration,
-                            true /* isNotInRecents */, null, null, represent.taskInfo,
-                            represent.allowEnterPip);
-                } else {
-                    return mAdaptors[0].mAnimationTarget;
+                final Rect unionBounds = new Rect();
+                for (int i = mAdaptors.length - 1; i >= 0; --i) {
+                    unionBounds.union(mAdaptors[i].mAnimationTarget.localBounds);
                 }
+                final WindowContainer wc = mAdaptors[0].mTarget;
+                final Task task = wc.asActivityRecord() != null
+                        ? wc.asActivityRecord().getTask() : wc.asTask();
+                final RemoteAnimationTarget represent = mAdaptors[0].mAnimationTarget;
+                final SurfaceControl leashSurface = new SurfaceControl.Builder()
+                        .setName("cross-animation-leash")
+                        .setContainerLayer()
+                        .setHidden(false)
+                        .setParent(task.getSurfaceControl())
+                        .build();
+                mCloseTransaction = new SurfaceControl.Transaction();
+                mCloseTransaction.reparent(leashSurface, null);
+                final SurfaceControl.Transaction pt = wc.getPendingTransaction();
+                pt.setLayer(leashSurface, wc.getParent().getLastLayer());
+                for (int i = mAdaptors.length - 1; i >= 0; --i) {
+                    BackWindowAnimationAdaptor adaptor = mAdaptors[i];
+                    pt.reparent(adaptor.mAnimationTarget.leash, leashSurface);
+                    pt.setPosition(adaptor.mAnimationTarget.leash,
+                            adaptor.mAnimationTarget.localBounds.left,
+                            adaptor.mAnimationTarget.localBounds.top);
+                    // For adjacent activity embedded, reparent Activity to TaskFragment when
+                    // animation finish
+                    final WindowContainer parent = adaptor.mTarget.getParent();
+                    if (parent != null) {
+                        mCloseTransaction.reparent(adaptor.mTarget.getSurfaceControl(),
+                                parent.getSurfaceControl());
+                    }
+                }
+                return new RemoteAnimationTarget(represent.taskId, represent.mode, leashSurface,
+                        represent.isTranslucent, represent.clipRect, represent.contentInsets,
+                        represent.prefixOrderIndex,
+                        new Point(unionBounds.left, unionBounds.top),
+                        unionBounds, unionBounds, represent.windowConfiguration,
+                        true /* isNotInRecents */, null, null, represent.taskInfo,
+                        represent.allowEnterPip);
+            }
+
+            void createStartingSurface(@NonNull WindowContainer closeWindow,
+                    ActivityRecord[] visibleOpenActivities) {
+                if (mAdaptors[0].mSwitchType == DIALOG_CLOSE) {
+                    return;
+                }
+                final WindowContainer mainOpen = mAdaptors[0].mTarget;
+                final int switchType = mAdaptors[0].mSwitchType;
+                final Task openTask = switchType == TASK_SWITCH
+                        ? mainOpen.asTask() : switchType == ACTIVITY_SWITCH
+                        ? mainOpen.asActivityRecord().getTask() : null;
+                if (openTask == null) {
+                    return;
+                }
+                final ActivityRecord mainActivity = switchType == ACTIVITY_SWITCH
+                        ? mainOpen.asActivityRecord()
+                        : openTask.getTopNonFinishingActivity();
+                if (mainActivity == null) {
+                    return;
+                }
+                final TaskSnapshot snapshot = getSnapshot(mainOpen, visibleOpenActivities);
+                mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
+                        .addWindowlessStartingSurface(openTask, mainActivity,
+                        // Choose configuration from closeWindow, because the configuration
+                        // of opening target may not update before resume, so the starting
+                        // surface should occlude it entirely.
+                        mRemoteAnimationTarget.leash, snapshot, closeWindow.getConfiguration(),
+                            new IWindowlessStartingSurfaceCallback.Stub() {
+                            // Once the starting surface has been created in shell, it will call
+                            // onSurfaceAdded to pass the created surface to core, so if a
+                            // transition is triggered by the back gesture, there doesn't need to
+                            // create another starting surface for the opening target, just reparent
+                            // the starting surface to the opening target.
+                            // Note if cleanUpWindowlessSurface happen prior than onSurfaceAdded
+                            // called, there won't be able to reparent the starting surface on
+                            // opening target. But if that happens and transition target is matched,
+                            // the app window should already draw.
+                                @Override
+                                public void onSurfaceAdded(SurfaceControl sc) {
+                                    synchronized (openTask.mWmService.mGlobalLock) {
+                                        if (mRequestedStartingSurfaceId != INVALID_TASK_ID) {
+                                            mStartingSurface = sc;
+                                        }
+                                    }
+                                }
+                            });
+            }
+
+            // When back gesture has triggered and transition target matches navigation target,
+            // reparent the starting surface to the opening target as it's starting window.
+            void reparentWindowlessSurfaceToTarget(SurfaceControl.Transaction reparentTransaction) {
+                if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
+                    return;
+                }
+                // If open target matches, reparent to open activity or task
+                if (mStartingSurface != null && mStartingSurface.isValid()) {
+                    SurfaceControl.Transaction transaction = reparentTransaction != null
+                            ? reparentTransaction : mAdaptors[0].mTarget.getPendingTransaction();
+                    if (mAdaptors.length == 1) {
+                        transaction.reparent(mStartingSurface,
+                                        mAdaptors[0].mTarget.getSurfaceControl());
+                    } else {
+                        // More than one opening window, reparent starting surface to leaf task.
+                        final WindowContainer wc = mAdaptors[0].mTarget;
+                        final Task task = wc.asActivityRecord() != null
+                                ? wc.asActivityRecord().getTask() : wc.asTask();
+                        transaction.reparent(mStartingSurface, task != null
+                                        ? task.getSurfaceControl()
+                                        : mAdaptors[0].mTarget.getSurfaceControl());
+                    }
+                    // remove starting surface.
+                    mStartingSurface = null;
+                }
+            }
+
+            /**
+             * Ask shell to clear the starting surface.
+             * @param openTransitionMatch if true, shell will play the remove starting window
+             *                            animation, otherwise remove it directly.
+             */
+            void cleanUpWindowlessSurface(boolean openTransitionMatch) {
+                if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
+                    return;
+                }
+                mAdaptors[0].mTarget.mWmService.mAtmService.mTaskOrganizerController
+                        .removeWindowlessStartingSurface(mRequestedStartingSurfaceId,
+                                !openTransitionMatch);
+                mRequestedStartingSurfaceId = INVALID_TASK_ID;
             }
         }
 
@@ -1240,11 +1331,6 @@
             private RemoteAnimationTarget mAnimationTarget;
             private final int mSwitchType;
 
-            // The starting surface task Id. Used to clear the starting surface if the animation has
-            // requested one during animating.
-            private int mRequestedStartingSurfaceId = INVALID_TASK_ID;
-            private SurfaceControl mStartingSurface;
-
             BackWindowAnimationAdaptor(@NonNull WindowContainer target, boolean isOpen,
                     int switchType) {
                 mBounds.set(target.getBounds());
@@ -1276,8 +1362,6 @@
             public void onAnimationCancelled(SurfaceControl animationLeash) {
                 if (mCapturedLeash == animationLeash) {
                     mCapturedLeash = null;
-                    mRequestedStartingSurfaceId = INVALID_TASK_ID;
-                    mStartingSurface = null;
                 }
             }
 
@@ -1345,84 +1429,6 @@
                         r.checkEnterPictureInPictureAppOpsState());
                 return mAnimationTarget;
             }
-
-            void createStartingSurface(@NonNull WindowContainer closeWindow,
-                    @NonNull ActivityRecord[] visibleOpenActivities) {
-                if (!mIsOpen) {
-                    return;
-                }
-                if (mSwitchType == DIALOG_CLOSE) {
-                    return;
-                }
-                final Task openTask = mSwitchType == TASK_SWITCH
-                        ? mTarget.asTask() : mSwitchType == ACTIVITY_SWITCH
-                        ? mTarget.asActivityRecord().getTask() : null;
-                if (openTask == null) {
-                    return;
-                }
-                final ActivityRecord mainActivity = mSwitchType == ACTIVITY_SWITCH
-                        ? mTarget.asActivityRecord()
-                        : openTask.getTopNonFinishingActivity();
-                if (mainActivity == null) {
-                    return;
-                }
-                final TaskSnapshot snapshot = getSnapshot(mTarget, visibleOpenActivities);
-                mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
-                        .addWindowlessStartingSurface(openTask, mainActivity,
-                                // Choose configuration from closeWindow, because the configuration
-                                // of opening target may not update before resume, so the starting
-                                // surface should occlude it entirely.
-                                mAnimationTarget.leash, snapshot, closeWindow.getConfiguration(),
-                                new IWindowlessStartingSurfaceCallback.Stub() {
-                            // Once the starting surface has been created in shell, it will call
-                            // onSurfaceAdded to pass the created surface to core, so if a
-                            // transition is triggered by the back gesture, there doesn't need to
-                            // create another starting surface for the opening target, just reparent
-                            // the starting surface to the opening target.
-                            // Note if cleanUpWindowlessSurface happen prior than onSurfaceAdded
-                            // called, there won't be able to reparent the starting surface on
-                            // opening target. But if that happens and transition target is matched,
-                            // the app window should already draw.
-                                    @Override
-                                    public void onSurfaceAdded(SurfaceControl sc) {
-                                        synchronized (mTarget.mWmService.mGlobalLock) {
-                                            if (mRequestedStartingSurfaceId != INVALID_TASK_ID) {
-                                                mStartingSurface = sc;
-                                            }
-                                        }
-                                    }
-                                });
-            }
-
-            // When back gesture has triggered and transition target matches navigation target,
-            // reparent the starting surface to the opening target as it's starting window.
-            void reparentWindowlessSurfaceToTarget() {
-                if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
-                    return;
-                }
-                // If open target matches, reparent to open activity or task
-                if (mStartingSurface != null && mStartingSurface.isValid()) {
-                    mTarget.getPendingTransaction()
-                            .reparent(mStartingSurface, mTarget.getSurfaceControl());
-                    // remove starting surface.
-                    mStartingSurface = null;
-                }
-            }
-
-            /**
-             * Ask shell to clear the starting surface.
-             * @param openTransitionMatch if true, shell will play the remove starting window
-             *                            animation, otherwise remove it directly.
-             */
-            void cleanUpWindowlessSurface(boolean openTransitionMatch) {
-                if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
-                    return;
-                }
-                mTarget.mWmService.mAtmService.mTaskOrganizerController
-                        .removeWindowlessStartingSurface(mRequestedStartingSurfaceId,
-                                !openTransitionMatch);
-                mRequestedStartingSurfaceId = INVALID_TASK_ID;
-            }
         }
 
         ScheduleAnimationBuilder prepareAnimation(
@@ -1499,18 +1505,10 @@
              * @param visibleOpenActivities  The visible activities in opening targets.
              */
             private void applyPreviewStrategy(@NonNull WindowContainer closeWindow,
-                    @NonNull BackWindowAnimationAdaptor[] openAnimationAdaptor,
+                    @NonNull BackWindowAnimationAdaptorWrapper openAnimationAdaptor,
                     @NonNull ActivityRecord[] visibleOpenActivities) {
-                if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind
-                        // TODO (b/274997067) Draw two snapshot in a single starting surface.
-                        // We are using TaskId as the key of
-                        // StartingSurfaceDrawer#StartingWindowRecordManager, so we cannot create
-                        // two activity snapshot with WindowlessStartingWindow.
-                        // Try to draw two snapshot within a WindowlessStartingWindow, or find
-                        // another key for StartingWindowRecordManager.
-                        && openAnimationAdaptor.length == 1) {
-                    openAnimationAdaptor[0].createStartingSurface(closeWindow,
-                            visibleOpenActivities);
+                if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) {
+                    openAnimationAdaptor.createStartingSurface(closeWindow, visibleOpenActivities);
                 } else {
                     for (int i = visibleOpenActivities.length - 1; i >= 0; --i) {
                         setLaunchBehind(visibleOpenActivities[i]);
@@ -1541,7 +1539,7 @@
                 }
                 mCloseTarget.mTransitionController.mSnapshotController
                         .mActivitySnapshotController.clearOnBackPressedActivities();
-                applyPreviewStrategy(mCloseTarget, mOpenAnimAdaptor.mAdaptors, openingActivities);
+                applyPreviewStrategy(mCloseTarget, mOpenAnimAdaptor, openingActivities);
 
                 final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback();
                 final RemoteAnimationTarget[] targets = getAnimationTargets();
@@ -1565,7 +1563,6 @@
                                 // animation was canceled
                                 return;
                             }
-                            mOpenAnimAdaptor.onAnimationFinish();
                             if (!triggerBack) {
                                 clearBackAnimateTarget();
                             } else {
diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
index 5b4fb3e..e48e4e8 100644
--- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
@@ -87,11 +87,7 @@
     void scheduleTransactionItemNow(@NonNull IApplicationThread client,
             @NonNull ClientTransactionItem transactionItem) throws RemoteException {
         final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
-        if (transactionItem.isActivityLifecycleItem()) {
-            clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
-        } else {
-            clientTransaction.addCallback(transactionItem);
-        }
+        clientTransaction.addTransactionItem(transactionItem);
         scheduleTransaction(clientTransaction);
     }
 
@@ -115,11 +111,8 @@
         } else {
             // TODO(b/260873529): cleanup after launch.
             final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
-            if (transactionItem.isActivityLifecycleItem()) {
-                clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
-            } else {
-                clientTransaction.addCallback(transactionItem);
-            }
+            clientTransaction.addTransactionItem(transactionItem);
+
             scheduleTransaction(clientTransaction);
         }
     }
@@ -160,8 +153,8 @@
         } else {
             // TODO(b/260873529): cleanup after launch.
             final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
-            clientTransaction.addCallback(transactionItem);
-            clientTransaction.setLifecycleStateRequest(lifecycleItem);
+            clientTransaction.addTransactionItem(transactionItem);
+            clientTransaction.addTransactionItem(lifecycleItem);
             scheduleTransaction(clientTransaction);
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e743172..d3acd71 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1127,7 +1127,7 @@
 
         final ActivityRecord activity = w.mActivityRecord;
         if (activity != null && activity.isVisibleRequested()) {
-            activity.updateLetterboxSurface(w);
+            activity.updateLetterboxSurfaceIfNeeded(w);
             final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);
             if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {
                 mTmpUpdateAllDrawn.add(activity);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index a7bbc25..5cf9acd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -104,7 +104,6 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.DisplayInfo;
@@ -2070,8 +2069,7 @@
             }
             return false;
         }
-        if (mCachedDecorInsets != null && !mCachedDecorInsets.canPreserve()
-                && !mDisplayContent.isSleeping()) {
+        if (mCachedDecorInsets != null && !mCachedDecorInsets.canPreserve() && mScreenOnFully) {
             mCachedDecorInsets = null;
         }
         mDecorInsets.invalidate();
@@ -2136,16 +2134,6 @@
         }
         mCachedDecorInsets.mPreserveId =
                 mDisplayContent.mTransitionController.getCollectingTransitionId();
-        // The validator will run after the transition is finished. So if the insets are changed
-        // during the transition, it can update to the latest state.
-        mDisplayContent.mTransitionController.mStateValidators.add(() -> {
-            // The insets provider client may defer to change its window until screen is on. So
-            // only validate when awake to avoid the cache being always dropped.
-            if (!mDisplayContent.isSleeping() && updateDecorInsetsInfo()) {
-                Slog.d(TAG, "Insets changed after display switch transition");
-                mDisplayContent.sendNewConfiguration();
-            }
-        });
     }
 
     @NavigationBarPosition
@@ -2891,9 +2879,6 @@
         if (!CLIENT_TRANSIENT) {
             mSystemGestures.dump(pw, prefix);
         }
-
-        pw.print(prefix); pw.println("Looper state:");
-        mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
     }
 
     private boolean supportsPointerLocation() {
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index edf9da1..5d613cf 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -52,7 +52,6 @@
 import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
 import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_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.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
 import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
@@ -924,21 +923,21 @@
         return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
     }
 
-    void updateLetterboxSurface(WindowState winHint) {
-        updateLetterboxSurface(winHint, mActivityRecord.getSyncTransaction());
+    void updateLetterboxSurfaceIfNeeded(WindowState winHint) {
+        updateLetterboxSurfaceIfNeeded(winHint, mActivityRecord.getSyncTransaction());
     }
 
-    void updateLetterboxSurface(WindowState winHint, Transaction t) {
+    void updateLetterboxSurfaceIfNeeded(WindowState winHint, Transaction t) {
         if (shouldNotLayoutLetterbox(winHint)) {
             return;
         }
-        layoutLetterbox(winHint);
+        layoutLetterboxIfNeeded(winHint);
         if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
             mLetterbox.applySurfaceChanges(t);
         }
     }
 
-    void layoutLetterbox(WindowState w) {
+    void layoutLetterboxIfNeeded(WindowState w) {
         if (shouldNotLayoutLetterbox(w)) {
             return;
         }
@@ -1369,23 +1368,25 @@
      *
      * <p>Conditions that needs to be met:
      * <ul>
-     *   <li>Activity is portrait-only.
-     *   <li>Fullscreen window in landscape device orientation.
+     *   <li>Windowing mode is fullscreen.
      *   <li>Horizontal Reachability is enabled.
-     *   <li>Activity fills parent vertically.
+     *   <li>First top opaque activity fills parent vertically, but not horizontally.
      * </ul>
      */
     private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
         // Use screen resolved bounds which uses resolved bounds or size compat bounds
         // as activity bounds can sometimes be empty
+        final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior()
+                ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds()
+                : mActivityRecord.getScreenResolvedBounds();
         return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
                 && parentConfiguration.windowConfiguration.getWindowingMode()
                         == WINDOWING_MODE_FULLSCREEN
-                && (parentConfiguration.orientation == ORIENTATION_LANDSCAPE
-                        && mActivityRecord.getOrientationForReachability() == ORIENTATION_PORTRAIT)
                 // Check whether the activity fills the parent vertically.
                 && parentConfiguration.windowConfiguration.getAppBounds().height()
-                        <= mActivityRecord.getScreenResolvedBounds().height();
+                        <= opaqueActivityBounds.height()
+                && parentConfiguration.windowConfiguration.getAppBounds().width()
+                        > opaqueActivityBounds.width();
     }
 
     @VisibleForTesting
@@ -1402,23 +1403,25 @@
      *
      * <p>Conditions that needs to be met:
      * <ul>
-     *   <li>Activity is landscape-only.
-     *   <li>Fullscreen window in portrait device orientation.
+     *   <li>Windowing mode is fullscreen.
      *   <li>Vertical Reachability is enabled.
-     *   <li>Activity fills parent horizontally.
+     *   <li>First top opaque activity fills parent horizontally but not vertically.
      * </ul>
      */
     private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
         // Use screen resolved bounds which uses resolved bounds or size compat bounds
         // as activity bounds can sometimes be empty
+        final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior()
+                ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds()
+                : mActivityRecord.getScreenResolvedBounds();
         return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
                 && parentConfiguration.windowConfiguration.getWindowingMode()
                         == WINDOWING_MODE_FULLSCREEN
-                && (parentConfiguration.orientation == ORIENTATION_PORTRAIT
-                        && mActivityRecord.getOrientationForReachability() == ORIENTATION_LANDSCAPE)
                 // Check whether the activity fills the parent horizontally.
-                && parentConfiguration.windowConfiguration.getBounds().width()
-                        == mActivityRecord.getScreenResolvedBounds().width();
+                && parentConfiguration.windowConfiguration.getAppBounds().width()
+                        <= opaqueActivityBounds.width()
+                && parentConfiguration.windowConfiguration.getAppBounds().height()
+                        > opaqueActivityBounds.height();
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bf45804..19a9b3f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1452,7 +1452,7 @@
             return false;
         }
 
-        if (enableHomeDelay() && !mService.mAmInternal.getThemeOverlayReadiness()) {
+        if (enableHomeDelay() && !mService.mAmInternal.isThemeOverlayReady(userId)) {
             Slog.d(TAG, "ThemeHomeDelay: Home launch was deferred.");
             return false;
         }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 975208f..908cbd3 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -110,9 +110,7 @@
     private final String mStringName;
     SurfaceSession mSurfaceSession;
     private final ArrayList<WindowState> mAddedWindows = new ArrayList<>();
-    // Set of visible application overlay window surfaces connected to this session.
-    private final ArraySet<WindowSurfaceController> mAppOverlaySurfaces = new ArraySet<>();
-    // Set of visible alert window surfaces connected to this session.
+    /** Set of visible alert/app-overlay window surfaces connected to this session. */
     private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
     private final DragDropController mDragDropController;
     final boolean mCanAddInternalSystemWindow;
@@ -796,46 +794,45 @@
         }
 
         boolean changed;
-
-        if (!mCanAddInternalSystemWindow && !mCanCreateSystemApplicationOverlay) {
-            // We want to track non-system apps adding alert windows so we can post an
-            // on-going notification for the user to control their visibility.
-            if (visible) {
-                changed = mAlertWindowSurfaces.add(surfaceController);
-                MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, true);
-            } else {
-                changed = mAlertWindowSurfaces.remove(surfaceController);
-                MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, true);
+        // Track non-system apps adding overlay/alert windows, so a notification can post for the
+        // user to control their visibility.
+        final boolean noSystemOverlayPermission =
+                !mCanAddInternalSystemWindow && !mCanCreateSystemApplicationOverlay;
+        if (visible) {
+            changed = mAlertWindowSurfaces.add(surfaceController);
+            if (type == TYPE_APPLICATION_OVERLAY) {
+                MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type,
+                        false /* set false to only log for TYPE_APPLICATION_OVERLAY */);
+            } else if (noSystemOverlayPermission) {
+                MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type,
+                        true /* only log for non-TYPE_APPLICATION_OVERLAY */);
             }
+        } else {
+            changed = mAlertWindowSurfaces.remove(surfaceController);
+            if (type == TYPE_APPLICATION_OVERLAY) {
+                MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type,
+                        false /* set false to only log for TYPE_APPLICATION_OVERLAY */);
+            } else if (noSystemOverlayPermission) {
+                MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type,
+                        true /* only log for non-TYPE_APPLICATION_OVERLAY */);
+            }
+        }
 
-            if (changed) {
-                if (mAlertWindowSurfaces.isEmpty()) {
-                    cancelAlertWindowNotification();
-                } else if (mAlertWindowNotification == null){
-                    mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName);
-                    if (mShowingAlertWindowNotificationAllowed) {
-                        mAlertWindowNotification.post();
-                    }
+        if (changed && noSystemOverlayPermission) {
+            if (mAlertWindowSurfaces.isEmpty()) {
+                cancelAlertWindowNotification();
+            } else if (mAlertWindowNotification == null) {
+                mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName);
+                if (mShowingAlertWindowNotificationAllowed) {
+                    mAlertWindowNotification.post();
                 }
             }
         }
 
-        if (type != TYPE_APPLICATION_OVERLAY) {
-            return;
-        }
-
-        if (visible) {
-            changed = mAppOverlaySurfaces.add(surfaceController);
-            MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type, false);
-        } else {
-            changed = mAppOverlaySurfaces.remove(surfaceController);
-            MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type, false);
-        }
-
-        if (changed) {
-            // Notify activity manager of changes to app overlay windows so it can adjust the
-            // importance score for the process.
-            setHasOverlayUi(!mAppOverlaySurfaces.isEmpty());
+        if (changed && mPid != WindowManagerService.MY_PID) {
+            // Notify activity manager that the process contains overlay/alert windows, so it can
+            // adjust the importance score for the process.
+            setHasOverlayUi(!mAlertWindowSurfaces.isEmpty());
         }
     }
 
@@ -870,12 +867,12 @@
         mSurfaceSession = null;
         mAddedWindows.clear();
         mAlertWindowSurfaces.clear();
-        mAppOverlaySurfaces.clear();
         setHasOverlayUi(false);
         cancelAlertWindowNotification();
     }
 
-    private void setHasOverlayUi(boolean hasOverlayUi) {
+    @VisibleForTesting
+    void setHasOverlayUi(boolean hasOverlayUi) {
         mService.mH.obtainMessage(H.SET_HAS_OVERLAY_UI, mPid, hasOverlayUi ? 1 : 0).sendToTarget();
     }
 
@@ -890,7 +887,6 @@
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("numWindow="); pw.print(mAddedWindows.size());
                 pw.print(" mCanAddInternalSystemWindow="); pw.print(mCanAddInternalSystemWindow);
-                pw.print(" mAppOverlaySurfaces="); pw.print(mAppOverlaySurfaces);
                 pw.print(" mAlertWindowSurfaces="); pw.print(mAlertWindowSurfaces);
                 pw.print(" mClientDead="); pw.print(mClientDead);
                 pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 838ce86..10cbc66 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1590,7 +1590,7 @@
                             mAtmService.getLifecycleManager().scheduleTransactionItem(
                                     appThread, activityResultItem);
                         } else {
-                            transaction.addCallback(activityResultItem);
+                            transaction.addTransactionItem(activityResultItem);
                         }
                     }
                 }
@@ -1602,7 +1602,7 @@
                         mAtmService.getLifecycleManager().scheduleTransactionItem(
                                 appThread, newIntentItem);
                     } else {
-                        transaction.addCallback(newIntentItem);
+                        transaction.addTransactionItem(newIntentItem);
                     }
                 }
 
@@ -1624,7 +1624,7 @@
                     mAtmService.getLifecycleManager().scheduleTransactionItem(
                             appThread, resumeActivityItem);
                 } else {
-                    transaction.setLifecycleStateRequest(resumeActivityItem);
+                    transaction.addTransactionItem(resumeActivityItem);
                     mAtmService.getLifecycleManager().scheduleTransaction(transaction);
                 }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e538f5d5..61480d2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6750,11 +6750,6 @@
     private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
         pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
-        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
-    }
-
-    private void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
-            ArrayList<WindowState> windows) {
         mRoot.dumpWindowsNoHeader(pw, dumpAll, windows);
 
         if (!mHidingNonSystemOverlayWindows.isEmpty()) {
@@ -6989,9 +6984,15 @@
         if (reason != null) {
             pw.println("  Reason: " + reason);
         }
+        pw.println();
+        final ArrayList<WindowState> relatedWindows = new ArrayList<>();
         for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {
             final DisplayContent dc = mRoot.getChildAt(i);
             final int displayId = dc.getDisplayId();
+            final WindowState currentFocus = dc.mCurrentFocus;
+            final ActivityRecord focusedApp = dc.mFocusedApp;
+            pw.println("  Display #" + displayId + " currentFocus=" + currentFocus
+                    + " focusedApp=" + focusedApp);
             if (!dc.mWinAddedSinceNullFocus.isEmpty()) {
                 pw.println("  Windows added in display #" + displayId + " since null focus: "
                         + dc.mWinAddedSinceNullFocus);
@@ -7000,12 +7001,25 @@
                 pw.println("  Windows removed in display #" + displayId + " since null focus: "
                         + dc.mWinRemovedSinceNullFocus);
             }
+            pw.println("  Tasks in top down Z order:");
+            dc.forAllTaskDisplayAreas(tda -> {
+                tda.dump(pw, "    ", false /* dumpAll */);
+            });
+            dc.getInputMonitor().dump(pw, "  ");
+            pw.println();
+            dc.forAllWindows(w -> {
+                if ((currentFocus != null && Objects.equals(w.mAttrs.packageName,
+                        currentFocus.mAttrs.packageName)) || (focusedApp != null
+                        && Objects.equals(w.mAttrs.packageName, focusedApp.packageName))) {
+                    relatedWindows.add(w);
+                }
+            }, true /* traverseTopToBottom */);
         }
+        if (windowState != null && !relatedWindows.contains(windowState)) {
+            relatedWindows.add(windowState);
+        }
+        mRoot.dumpWindowsNoHeader(pw, true /* dumpAll */, relatedWindows);
         pw.println();
-        dumpWindowsNoHeaderLocked(pw, true, null);
-        pw.println();
-        pw.println("Last ANR continued");
-        mRoot.dumpDisplayContents(pw);
         pw.close();
         mLastANRState = sw.toString();
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 6acf1f3..ee16a37 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -28,7 +28,6 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.server.am.ProcessList.INVALID_ADJ;
-import static com.android.server.grammaticalinflection.GrammaticalInflectionUtils.checkSystemGrammaticalGenderPermission;
 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;
@@ -299,7 +298,7 @@
      */
     private volatile int mActivityStateFlags = ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
 
-    private boolean mCanUseSystemGrammaticalGender;
+    private final boolean mCanUseSystemGrammaticalGender;
 
     public WindowProcessController(@NonNull ActivityTaskManagerService atm,
             @NonNull ApplicationInfo info, String name, int uid, int userId, Object owner,
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6e993b3..b8f1d15 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1332,7 +1332,7 @@
         updateSourceFrame(windowFrames.mFrame);
 
         if (mActivityRecord != null && !mIsChildWindow) {
-            mActivityRecord.layoutLetterbox(this);
+            mActivityRecord.layoutLetterboxIfNeeded(this);
         }
         mSurfacePlacementNeeded = true;
         mHaveFrame = true;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 17638fc..dc8cec9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -21,8 +21,6 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 import static android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST;
 import static android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST;
-import static android.app.admin.flags.Flags.dumpsysPolicyEngineMigrationEnabled;
-import static android.app.admin.flags.Flags.policyEngineMigrationV2Enabled;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 
 import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
@@ -41,6 +39,7 @@
 import android.app.admin.PasswordPolicy;
 import android.app.admin.PreferentialNetworkServiceConfig;
 import android.app.admin.WifiSsidPolicy;
+import android.app.admin.flags.Flags;
 import android.graphics.Color;
 import android.net.wifi.WifiSsid;
 import android.os.Bundle;
@@ -1297,7 +1296,7 @@
         pw.print("encryptionRequested=");
         pw.println(encryptionRequested);
 
-        if (!dumpsysPolicyEngineMigrationEnabled()) {
+        if (!Flags.dumpsysPolicyEngineMigrationEnabled()) {
             pw.print("disableCamera=");
             pw.println(disableCamera);
 
@@ -1316,7 +1315,8 @@
             UserRestrictionsUtils.dumpRestrictions(pw, "  ", userRestrictions);
         }
 
-        if (!policyEngineMigrationV2Enabled() || !dumpsysPolicyEngineMigrationEnabled()) {
+        if (!Flags.policyEngineMigrationV2Enabled()
+                || !Flags.dumpsysPolicyEngineMigrationEnabled()) {
             pw.print("mUsbDataSignaling=");
             pw.println(mUsbDataSignalingEnabled);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 0ccf810c..12f4407 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -24,7 +24,6 @@
 import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_STORAGE_LIMIT_REACHED;
 import static android.app.admin.PolicyUpdateResult.RESULT_POLICY_CLEARED;
 import static android.app.admin.PolicyUpdateResult.RESULT_POLICY_SET;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
 import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT;
 
 import android.Manifest;
@@ -42,6 +41,7 @@
 import android.app.admin.PolicyValue;
 import android.app.admin.TargetUser;
 import android.app.admin.UserRestrictionPolicyKey;
+import android.app.admin.flags.Flags;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -225,7 +225,7 @@
 
         synchronized (mLock) {
             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
-            if (devicePolicySizeTrackingEnabled()) {
+            if (Flags.devicePolicySizeTrackingEnabled() && false) {
                 if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value,
                         policyDefinition, userId)) {
                     return;
@@ -350,7 +350,7 @@
             }
             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
 
-            if (devicePolicySizeTrackingEnabled()) {
+            if (Flags.devicePolicySizeTrackingEnabled() && false) {
                 decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin);
             }
 
@@ -496,7 +496,7 @@
 
         synchronized (mLock) {
             PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
-            if (devicePolicySizeTrackingEnabled()) {
+            if (Flags.devicePolicySizeTrackingEnabled() && false) {
                 if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value,
                         policyDefinition, UserHandle.USER_ALL)) {
                     return;
@@ -568,7 +568,7 @@
         synchronized (mLock) {
             PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
 
-            if (devicePolicySizeTrackingEnabled()) {
+            if (Flags.devicePolicySizeTrackingEnabled() && false) {
                 decreasePolicySizeForAdmin(policyState, enforcingAdmin);
             }
 
@@ -1892,7 +1892,7 @@
 
         private void writeEnforcingAdminSizeInner(TypedXmlSerializer serializer)
                 throws IOException {
-            if (devicePolicySizeTrackingEnabled()) {
+            if (Flags.devicePolicySizeTrackingEnabled() && false) {
                 if (mAdminPolicySize != null) {
                     for (int i = 0; i < mAdminPolicySize.size(); i++) {
                         int userId = mAdminPolicySize.keyAt(i);
@@ -1916,7 +1916,7 @@
 
         private void writeMaxPolicySizeInner(TypedXmlSerializer serializer)
                 throws IOException {
-            if (!devicePolicySizeTrackingEnabled()) {
+            if (!Flags.devicePolicySizeTrackingEnabled() || true) {
                 return;
             }
             serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
@@ -2081,7 +2081,7 @@
 
         private void readMaxPolicySizeInner(TypedXmlPullParser parser)
                 throws XmlPullParserException, IOException {
-            if (!devicePolicySizeTrackingEnabled()) {
+            if (!Flags.devicePolicySizeTrackingEnabled() || true) {
                 return;
             }
             mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ffc090f..d5d26be 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -239,14 +239,6 @@
 import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNER_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED;
 import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED;
-import static android.app.admin.flags.Flags.backupServiceSecurityLogEventEnabled;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
-import static android.app.admin.flags.Flags.dumpsysPolicyEngineMigrationEnabled;
-import static android.app.admin.flags.Flags.headlessDeviceOwnerSingleUserEnabled;
-import static android.app.admin.flags.Flags.permissionMigrationForZeroTrustImplEnabled;
-import static android.app.admin.flags.Flags.policyEngineMigrationV2Enabled;
-import static android.app.admin.flags.Flags.assistContentUserRestrictionEnabled;
-import static android.app.admin.flags.Flags.securityLogV2Enabled;
 import static android.content.Intent.ACTION_MANAGED_PROFILE_AVAILABLE;
 import static android.content.Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -272,6 +264,7 @@
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
 import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
@@ -360,6 +353,7 @@
 import android.app.admin.UnsafeStateException;
 import android.app.admin.UserRestrictionPolicyKey;
 import android.app.admin.WifiSsidPolicy;
+import android.app.admin.flags.Flags;
 import android.app.backup.IBackupManager;
 import android.app.compat.CompatChanges;
 import android.app.role.OnRoleHoldersChangedListener;
@@ -513,7 +507,6 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.net.module.util.ProxyUtils;
-import com.android.net.thread.flags.Flags;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
@@ -2728,7 +2721,7 @@
             return;
         }
 
-        if (securityLogV2Enabled()) {
+        if (Flags.securityLogV2Enabled()) {
             boolean auditLoggingEnabled = Boolean.TRUE.equals(
                     mDevicePolicyEngine.getResolvedPolicy(
                             PolicyDefinition.AUDIT_LOGGING, UserHandle.USER_ALL));
@@ -3418,7 +3411,7 @@
 
     @GuardedBy("getLockObject()")
     private void maybeMigrateSecurityLoggingPolicyLocked() {
-        if (!securityLogV2Enabled() || mOwners.isSecurityLoggingMigrated()) {
+        if (!Flags.securityLogV2Enabled() || mOwners.isSecurityLoggingMigrated()) {
             return;
         }
 
@@ -3522,7 +3515,7 @@
             }
 
             revertTransferOwnershipIfNecessaryLocked();
-            if (!policyEngineMigrationV2Enabled()) {
+            if (!Flags.policyEngineMigrationV2Enabled()) {
                 updateUsbDataSignal(mContext, isUsbDataSignalingEnabledInternalLocked());
             }
         }
@@ -11151,7 +11144,7 @@
                 pw.println();
                 mStatLogger.dump(pw);
                 pw.println();
-                if (dumpsysPolicyEngineMigrationEnabled()) {
+                if (Flags.dumpsysPolicyEngineMigrationEnabled()) {
                     mDevicePolicyEngine.dump(pw);
                     pw.println();
                 }
@@ -12068,7 +12061,7 @@
         }
 
         if (packageList != null) {
-            if (!devicePolicySizeTrackingEnabled()) {
+            if (!Flags.devicePolicySizeTrackingEnabled()) {
                 for (String pkg : packageList) {
                     PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
                 }
@@ -12313,7 +12306,7 @@
         Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
         checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
 
-        if (headlessDeviceOwnerSingleUserEnabled()) {
+        if (Flags.headlessDeviceOwnerSingleUserEnabled()) {
             // Block this method if the device is in headless main user mode
             Preconditions.checkCallAuthorization(
                     getHeadlessDeviceOwnerMode() != HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER,
@@ -13438,12 +13431,12 @@
                 UserManager.DISALLOW_SMS, new String[]{MANAGE_DEVICE_POLICY_SMS});
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, new String[]{MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS});
-        if (Flags.threadUserRestrictionEnabled()) {
+        if (com.android.net.thread.flags.Flags.threadUserRestrictionEnabled()) {
             USER_RESTRICTION_PERMISSIONS.put(
                     UserManager.DISALLOW_THREAD_NETWORK,
                     new String[]{MANAGE_DEVICE_POLICY_THREAD_NETWORK});
         }
-        if (assistContentUserRestrictionEnabled()) {
+        if (Flags.assistContentUserRestrictionEnabled()) {
             USER_RESTRICTION_PERMISSIONS.put(
                     UserManager.DISALLOW_ASSIST_CONTENT,
                     new String[]{MANAGE_DEVICE_POLICY_ASSIST_CONTENT});
@@ -13777,7 +13770,7 @@
             return;
         }
 
-        if (!devicePolicySizeTrackingEnabled()) {
+        if (!Flags.devicePolicySizeTrackingEnabled()) {
             PolicySizeVerifier.enforceMaxStringLength(accountType, "account type");
         }
 
@@ -14391,7 +14384,7 @@
     public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
             throws SecurityException {
         Objects.requireNonNull(packages, "packages is null");
-        if (!devicePolicySizeTrackingEnabled()) {
+        if (!Flags.devicePolicySizeTrackingEnabled()) {
             for (String pkg : packages) {
                 PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
             }
@@ -15798,7 +15791,7 @@
 
         @Override
         public void enforceSecurityLoggingPolicy(boolean enabled) {
-            if (!securityLogV2Enabled()) {
+            if (!Flags.securityLogV2Enabled()) {
                 return;
             }
             Boolean auditLoggingEnabled = mDevicePolicyEngine.getResolvedPolicy(
@@ -15808,7 +15801,7 @@
 
         @Override
         public void enforceAuditLoggingPolicy(boolean enabled) {
-            if (!securityLogV2Enabled()) {
+            if (!Flags.securityLogV2Enabled()) {
                 return;
             }
             Boolean securityLoggingEnabled = mDevicePolicyEngine.getResolvedPolicy(
@@ -16345,7 +16338,7 @@
                     mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
                 }
 
-                if (permissionMigrationForZeroTrustImplEnabled()) {
+                if (Flags.permissionMigrationForZeroTrustImplEnabled()) {
                     final UserHandle user = UserHandle.of(userId);
                     final String roleHolderPackage = getRoleHolderPackageNameOnUser(
                             RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, userId);
@@ -16359,7 +16352,7 @@
 
     @Override
     public SystemUpdateInfo getPendingSystemUpdate(ComponentName admin, String callerPackage) {
-        if (permissionMigrationForZeroTrustImplEnabled()) {
+        if (Flags.permissionMigrationForZeroTrustImplEnabled()) {
             CallerIdentity caller = getCallerIdentity(admin, callerPackage);
             enforcePermissions(new String[] {NOTIFY_PENDING_SYSTEM_UPDATE,
                     MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES}, caller.getPackageName(),
@@ -16816,7 +16809,7 @@
                     return STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED;
                 }
 
-                if (headlessDeviceOwnerSingleUserEnabled() && isHeadlessModeSingleUser) {
+                if (Flags.headlessDeviceOwnerSingleUserEnabled() && isHeadlessModeSingleUser) {
                     ensureSetUpUser = mUserManagerInternal.getMainUserId();
                     if (ensureSetUpUser == UserHandle.USER_NULL) {
                         return STATUS_HEADLESS_ONLY_SYSTEM_USER;
@@ -17723,7 +17716,7 @@
         }
         final CallerIdentity caller = getCallerIdentity(who, packageName);
 
-        if (securityLogV2Enabled()) {
+        if (Flags.securityLogV2Enabled()) {
             EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
                     who,
                     MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
@@ -17783,7 +17776,7 @@
             return mInjector.securityLogGetLoggingEnabledProperty();
         }
 
-        if (securityLogV2Enabled()) {
+        if (Flags.securityLogV2Enabled()) {
             final EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
                     admin,
                     MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
@@ -17881,7 +17874,7 @@
 
         final CallerIdentity caller = getCallerIdentity(admin, packageName);
 
-        if (securityLogV2Enabled()) {
+        if (Flags.securityLogV2Enabled()) {
             EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
                     admin,
                     MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
@@ -17936,7 +17929,7 @@
         }
         final CallerIdentity caller = getCallerIdentity(callingPackage);
 
-        if (!securityLogV2Enabled()) {
+        if (!Flags.securityLogV2Enabled()) {
             throw new UnsupportedOperationException("Audit log not enabled");
         }
 
@@ -17964,7 +17957,7 @@
             return false;
         }
 
-        if (!securityLogV2Enabled()) {
+        if (!Flags.securityLogV2Enabled()) {
             throw new UnsupportedOperationException("Audit log not enabled");
         }
 
@@ -18230,7 +18223,7 @@
 
         toggleBackupServiceActive(caller.getUserId(), enabled);
 
-        if (backupServiceSecurityLogEventEnabled()) {
+        if (Flags.backupServiceSecurityLogEventEnabled()) {
             if (SecurityLog.isLoggingEnabled()) {
                 SecurityLog.writeEvent(SecurityLog.TAG_BACKUP_SERVICE_TOGGLED,
                         caller.getPackageName(), caller.getUserId(), enabled ? 1 : 0);
@@ -20951,7 +20944,7 @@
 
         final CallerIdentity caller = getCallerIdentity(callerPackage);
 
-        if (permissionMigrationForZeroTrustImplEnabled()) {
+        if (Flags.permissionMigrationForZeroTrustImplEnabled()) {
             enforcePermission(MANAGE_DEVICE_POLICY_CERTIFICATES, caller.getPackageName());
         } else {
             Preconditions.checkCallAuthorization(
@@ -21555,7 +21548,7 @@
             setTimeAndTimezone(provisioningParams.getTimeZone(), provisioningParams.getLocalTime());
             setLocale(provisioningParams.getLocale());
 
-            int deviceOwnerUserId = headlessDeviceOwnerSingleUserEnabled()
+            int deviceOwnerUserId = Flags.headlessDeviceOwnerSingleUserEnabled()
                     && getHeadlessDeviceOwnerMode() == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER
                     ? mUserManagerInternal.getMainUserId()
                     : UserHandle.USER_SYSTEM;
@@ -21932,7 +21925,7 @@
         Objects.requireNonNull(packageName, "Admin package name must be provided");
         final CallerIdentity caller = getCallerIdentity(packageName);
 
-        if (!policyEngineMigrationV2Enabled()) {
+        if (!Flags.policyEngineMigrationV2Enabled()) {
             Preconditions.checkCallAuthorization(
                     isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
                     "USB data signaling can only be controlled by a device owner or "
@@ -21942,7 +21935,7 @@
         }
 
         synchronized (getLockObject()) {
-            if (policyEngineMigrationV2Enabled()) {
+            if (Flags.policyEngineMigrationV2Enabled()) {
                 EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
                         /* admin= */ null, MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
                         caller.getPackageName(),
@@ -21982,7 +21975,7 @@
     @Override
     public boolean isUsbDataSignalingEnabled(String packageName) {
         final CallerIdentity caller = getCallerIdentity(packageName);
-        if (policyEngineMigrationV2Enabled()) {
+        if (Flags.policyEngineMigrationV2Enabled()) {
             Boolean enabled = mDevicePolicyEngine.getResolvedPolicy(
                     PolicyDefinition.USB_DATA_SIGNALING,
                     caller.getUserId());
@@ -22107,9 +22100,9 @@
         enforcePermission(MANAGE_DEVICE_POLICY_THEFT_DETECTION, caller.getPackageName(),
                 caller.getUserId());
 
-        //STOPSHIP: replace 1<<9 with
-        // LockPatternUtils.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST once ag/26042068 lands
-        return 0 != (mLockPatternUtils.getStrongAuthForUser(caller.getUserId()) & (1 << 9));
+        return mInjector.binderWithCleanCallingIdentity(() ->
+                0 != (mLockPatternUtils.getStrongAuthForUser(caller.getUserId())
+                        & SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST));
     }
 
     @Override
@@ -24235,7 +24228,7 @@
 
     @Override
     public void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit) {
-        if (!devicePolicySizeTrackingEnabled()) {
+        if (!Flags.devicePolicySizeTrackingEnabled() || true) {
             return;
         }
         CallerIdentity caller = getCallerIdentity(callerPackageName);
@@ -24247,7 +24240,7 @@
 
     @Override
     public int getMaxPolicyStorageLimit(String callerPackageName) {
-        if (!devicePolicySizeTrackingEnabled()) {
+        if (!Flags.devicePolicySizeTrackingEnabled() || true) {
             return -1;
         }
         CallerIdentity caller = getCallerIdentity(callerPackageName);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index d9fef10..9d73ed0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -16,11 +16,11 @@
 package com.android.server.devicepolicy;
 
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
-import static android.app.admin.flags.Flags.securityLogV2Enabled;
 
 import android.annotation.Nullable;
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
+import android.app.admin.flags.Flags;
 import android.content.ComponentName;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -400,7 +400,7 @@
 
             out.startTag(null, TAG_POLICY_ENGINE_MIGRATION);
             out.attributeBoolean(null, ATTR_MIGRATED_TO_POLICY_ENGINE, mMigratedToPolicyEngine);
-            if (securityLogV2Enabled()) {
+            if (Flags.securityLogV2Enabled()) {
                 out.attributeBoolean(null, ATTR_SECURITY_LOG_MIGRATED, mSecurityLoggingMigrated);
             }
             out.endTag(null, TAG_POLICY_ENGINE_MIGRATION);
@@ -463,7 +463,7 @@
                 case TAG_POLICY_ENGINE_MIGRATION:
                     mMigratedToPolicyEngine = parser.getAttributeBoolean(
                             null, ATTR_MIGRATED_TO_POLICY_ENGINE, false);
-                    mSecurityLoggingMigrated = securityLogV2Enabled()
+                    mSecurityLoggingMigrated = Flags.securityLogV2Enabled()
                             && parser.getAttributeBoolean(null, ATTR_SECURITY_LOG_MIGRATED, false);
                     break;
                 default:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index e8c5658..8cb511e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -17,11 +17,11 @@
 package com.android.server.devicepolicy;
 
 import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
-import static android.app.admin.flags.Flags.defaultSmsPersonalAppSuspensionFixEnabled;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.admin.flags.Flags;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -206,7 +206,7 @@
 
     private String getDefaultSmsPackage() {
         //TODO(b/319449037): Unflag the following change.
-        if (defaultSmsPersonalAppSuspensionFixEnabled()) {
+        if (Flags.defaultSmsPersonalAppSuspensionFixEnabled()) {
             return SmsApplication.getDefaultSmsApplicationAsUser(
                             mContext, /*updateIfNeeded=*/ false, mContext.getUser())
                     .getPackageName();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index b6ab4c7..c582a46 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -16,8 +16,6 @@
 
 package com.android.server.devicepolicy;
 
-import static android.app.admin.flags.Flags.securityLogV2Enabled;
-
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
@@ -25,6 +23,7 @@
 import android.app.admin.IAuditLogEventsCallback;
 import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
+import android.app.admin.flags.Flags;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
@@ -468,11 +467,11 @@
             assignLogId(event);
         }
 
-        if (!securityLogV2Enabled() || mLegacyLogEnabled) {
+        if (!Flags.securityLogV2Enabled() || mLegacyLogEnabled) {
             addToLegacyBufferLocked(dedupedLogs);
         }
 
-        if (securityLogV2Enabled() && mAuditLogEnabled) {
+        if (Flags.securityLogV2Enabled() && mAuditLogEnabled) {
             addAuditLogEventsLocked(dedupedLogs);
         }
     }
@@ -549,7 +548,7 @@
                 saveLastEvents(newLogs);
                 newLogs.clear();
 
-                if (!securityLogV2Enabled() || mLegacyLogEnabled) {
+                if (!Flags.securityLogV2Enabled() || mLegacyLogEnabled) {
                     notifyDeviceOwnerOrProfileOwnerIfNeeded(force);
                 }
             } catch (IOException e) {
diff --git a/services/tests/PackageManagerServiceTests/apks/Android.bp b/services/tests/PackageManagerServiceTests/apks/Android.bp
index 6c91806..55f2bc9 100644
--- a/services/tests/PackageManagerServiceTests/apks/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install-split-base/Android.bp b/services/tests/PackageManagerServiceTests/apks/install-split-base/Android.bp
index 39992f6..2f5a57f 100644
--- a/services/tests/PackageManagerServiceTests/apks/install-split-base/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install-split-base/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install-split-feature-a/Android.bp b/services/tests/PackageManagerServiceTests/apks/install-split-feature-a/Android.bp
index ca7295e..fee9b02 100644
--- a/services/tests/PackageManagerServiceTests/apks/install-split-feature-a/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install-split-feature-a/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install/Android.bp b/services/tests/PackageManagerServiceTests/apks/install/Android.bp
index 12175fd..b0a2adb 100644
--- a/services/tests/PackageManagerServiceTests/apks/install/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_bad_dex/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_bad_dex/Android.bp
index ad75668..891ed29 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_bad_dex/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_bad_dex/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_complete_package_info/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_complete_package_info/Android.bp
index 98aa750..4f03bb9 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_complete_package_info/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_complete_package_info/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_decl_perm/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_decl_perm/Android.bp
index ef65f5d..452a6ad 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_decl_perm/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_decl_perm/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_intent_filters/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_intent_filters/Android.bp
index 643824d..b05f0ec 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_intent_filters/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_intent_filters/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_loc_auto/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_loc_auto/Android.bp
index 4e4ae52..1f1d901e 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_loc_auto/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_loc_auto/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_loc_internal/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_loc_internal/Android.bp
index 39cdd51..b04bb50 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_loc_internal/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_loc_internal/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_loc_sdcard/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_loc_sdcard/Android.bp
index ed82793..d0a5192 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_loc_sdcard/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_loc_sdcard/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_loc_unspecified/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_loc_unspecified/Android.bp
index fd15cb8..7f6b29e 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_loc_unspecified/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_target_sdk_22/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_target_sdk_22/Android.bp
index 69b26cc..8159bd1 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_target_sdk_22/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_target_sdk_22/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_target_sdk_23/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_target_sdk_23/Android.bp
index e3154db..9ce980f 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_target_sdk_23/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_target_sdk_23/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_use_perm_good/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_use_perm_good/Android.bp
index 959ffbc..e4a5728 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_use_perm_good/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_use_perm_good/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_uses_feature/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_uses_feature/Android.bp
index fa25af4..eb2f52a 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_uses_feature/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_uses_feature/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/install_uses_sdk/Android.bp b/services/tests/PackageManagerServiceTests/apks/install_uses_sdk/Android.bp
index 24e380c..46b4fc2 100644
--- a/services/tests/PackageManagerServiceTests/apks/install_uses_sdk/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/install_uses_sdk/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/apks/keyset/Android.bp b/services/tests/PackageManagerServiceTests/apks/keyset/Android.bp
index ce7919c..d86b51d 100644
--- a/services/tests/PackageManagerServiceTests/apks/keyset/Android.bp
+++ b/services/tests/PackageManagerServiceTests/apks/keyset/Android.bp
@@ -1,5 +1,6 @@
 //apks signed by keyset_A
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index c617ec4..6fd21f7 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp b/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
index e70a734..69d79c9 100644
--- a/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp
index aef365e..fe78d7d 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Apex/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index cea9c59..73cec6c 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp
index b826590..08e41e7 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp
index 92dcd34..2fe7f47 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Overlay/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
index ed5f2b5..e80b5b5 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayActor/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp
index 2bb6b82..a8b4dd1 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/OverlayTarget/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
index 93d70bb..c65a4ec 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_android_packages",
     // 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"
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java
index 3458b08..306b4f8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessWearBedtimeModeClamperTest.java
@@ -85,7 +85,7 @@
 
     @Test
     public void testType() {
-        assertEquals(BrightnessClamper.Type.BEDTIME_MODE, mClamper.getType());
+        assertEquals(BrightnessClamper.Type.WEAR_BEDTIME_MODE, mClamper.getType());
     }
 
     @Test
diff --git a/services/tests/dreamservicetests/Android.bp b/services/tests/dreamservicetests/Android.bp
index 8ef443e..5aa5d61 100644
--- a/services/tests/dreamservicetests/Android.bp
+++ b/services/tests/dreamservicetests/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["frameworks_base_license"],
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS
index b363f54..f801560 100644
--- a/services/tests/mockingservicestests/src/com/android/server/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS
@@ -2,3 +2,4 @@
 per-file *AppStateTracker* = file:/apex/jobscheduler/OWNERS
 per-file *DeviceIdleController* = file:/apex/jobscheduler/OWNERS
 per-file SensitiveContentProtectionManagerServiceTest.java = file:/core/java/android/permission/OWNERS
+per-file RescuePartyTest.java = file:/packages/CrashRecovery/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 2d065e2..211a83d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 
 import android.content.ContentResolver;
@@ -45,7 +46,6 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
-import android.sysprop.CrashRecoveryProperties;
 import android.util.ArraySet;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -64,6 +64,7 @@
 import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 
+import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -101,6 +102,7 @@
 
     private MockitoSession mSession;
     private HashMap<String, String> mSystemSettingsMap;
+    private HashMap<String, String> mCrashRecoveryPropertiesMap;
     //Records the namespaces wiped by setProperties().
     private HashSet<String> mNamespacesWiped;
 
@@ -113,6 +115,9 @@
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private PackageManager mPackageManager;
 
+    // Mock only sysprop apis
+    private PackageWatchdog.BootThreshold mSpyBootThreshold;
+
     @Captor
     private ArgumentCaptor<DeviceConfig.MonitorCallback> mMonitorCallbackCaptor;
     @Captor
@@ -208,11 +213,12 @@
         // Mock PackageWatchdog
         doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
                 .when(() -> PackageWatchdog.getInstance(mMockContext));
+        mockCrashRecoveryProperties(mMockPackageWatchdog);
 
         doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
 
-        CrashRecoveryProperties.rescueBootCount(0);
-        CrashRecoveryProperties.enableRescueParty(true);
+        setCrashRecoveryPropRescueBootCount(0);
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
     }
 
@@ -255,7 +261,7 @@
         noteBoot(4);
         assertTrue(RescueParty.isRebootPropertySet());
 
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         noteBoot(5);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -280,7 +286,7 @@
         noteAppCrash(4, true);
         assertTrue(RescueParty.isRebootPropertySet());
 
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         noteAppCrash(5, true);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -438,7 +444,7 @@
             noteBoot(i + 1);
         }
         assertFalse(RescueParty.isFactoryResetPropertySet());
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         noteBoot(LEVEL_FACTORY_RESET + 1);
         assertTrue(RescueParty.isAttemptingFactoryReset());
         assertTrue(RescueParty.isFactoryResetPropertySet());
@@ -456,7 +462,7 @@
         noteBoot(mitigationCount++);
         assertFalse(RescueParty.isFactoryResetPropertySet());
         noteBoot(mitigationCount++);
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         noteBoot(mitigationCount + 1);
         assertTrue(RescueParty.isAttemptingFactoryReset());
         assertTrue(RescueParty.isFactoryResetPropertySet());
@@ -464,10 +470,10 @@
 
     @Test
     public void testThrottlingOnBootFailures() {
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
         long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
-        CrashRecoveryProperties.lastFactoryResetTimeMs(beforeTimeout);
+        setCrashRecoveryPropLastFactoryReset(beforeTimeout);
         for (int i = 1; i <= LEVEL_FACTORY_RESET; i++) {
             noteBoot(i);
         }
@@ -476,10 +482,10 @@
 
     @Test
     public void testThrottlingOnAppCrash() {
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
         long beforeTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN - 1);
-        CrashRecoveryProperties.lastFactoryResetTimeMs(beforeTimeout);
+        setCrashRecoveryPropLastFactoryReset(beforeTimeout);
         for (int i = 0; i <= LEVEL_FACTORY_RESET; i++) {
             noteAppCrash(i + 1, true);
         }
@@ -488,10 +494,10 @@
 
     @Test
     public void testNotThrottlingAfterTimeoutOnBootFailures() {
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
         long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
-        CrashRecoveryProperties.lastFactoryResetTimeMs(afterTimeout);
+        setCrashRecoveryPropLastFactoryReset(afterTimeout);
         for (int i = 1; i <= LEVEL_FACTORY_RESET; i++) {
             noteBoot(i);
         }
@@ -499,10 +505,10 @@
     }
     @Test
     public void testNotThrottlingAfterTimeoutOnAppCrash() {
-        CrashRecoveryProperties.attemptingReboot(false);
+        setCrashRecoveryPropAttemptingReboot(false);
         long now = System.currentTimeMillis();
         long afterTimeout = now - TimeUnit.MINUTES.toMillis(THROTTLING_DURATION_MIN + 1);
-        CrashRecoveryProperties.lastFactoryResetTimeMs(afterTimeout);
+        setCrashRecoveryPropLastFactoryReset(afterTimeout);
         for (int i = 0; i <= LEVEL_FACTORY_RESET; i++) {
             noteAppCrash(i + 1, true);
         }
@@ -525,26 +531,26 @@
 
     @Test
     public void testExplicitlyEnablingAndDisablingRescue() {
-        CrashRecoveryProperties.enableRescueParty(false);
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
         SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
         assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), false);
 
-        CrashRecoveryProperties.enableRescueParty(true);
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
         assertTrue(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1));
     }
 
     @Test
     public void testDisablingRescueByDeviceConfigFlag() {
-        CrashRecoveryProperties.enableRescueParty(false);
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true));
 
         assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
                 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), false);
 
         // Restore the property value initialized in SetUp()
-        CrashRecoveryProperties.enableRescueParty(true);
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
         SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
     }
 
@@ -753,4 +759,138 @@
         RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
                 packageName, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
     }
+
+    // Mock CrashRecoveryProperties as they cannot be accessed due to SEPolicy restrictions
+    private void mockCrashRecoveryProperties(PackageWatchdog watchdog) {
+        // mock properties in RescueParty
+        try {
+
+            doAnswer((Answer<Boolean>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.attempting_factory_reset", "false");
+                return Boolean.parseBoolean(storedValue);
+            }).when(() -> RescueParty.isFactoryResetPropertySet());
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                boolean value = invocationOnMock.getArgument(0);
+                mCrashRecoveryPropertiesMap.put("crashrecovery.attempting_factory_reset",
+                        Boolean.toString(value));
+                return null;
+            }).when(() -> RescueParty.setFactoryResetProperty(anyBoolean()));
+
+            doAnswer((Answer<Boolean>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.attempting_reboot", "false");
+                return Boolean.parseBoolean(storedValue);
+            }).when(() -> RescueParty.isRebootPropertySet());
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                boolean value = invocationOnMock.getArgument(0);
+                setCrashRecoveryPropAttemptingReboot(value);
+                return null;
+            }).when(() -> RescueParty.setRebootProperty(anyBoolean()));
+
+            doAnswer((Answer<Long>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("persist.crashrecovery.last_factory_reset", "0");
+                return Long.parseLong(storedValue);
+            }).when(() -> RescueParty.getLastFactoryResetTimeMs());
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                long value = invocationOnMock.getArgument(0);
+                setCrashRecoveryPropLastFactoryReset(value);
+                return null;
+            }).when(() -> RescueParty.setLastFactoryResetTimeMs(anyLong()));
+
+            doAnswer((Answer<Integer>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.max_rescue_level_attempted", "0");
+                return Integer.parseInt(storedValue);
+            }).when(() -> RescueParty.getMaxRescueLevelAttempted());
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                int value = invocationOnMock.getArgument(0);
+                mCrashRecoveryPropertiesMap.put("crashrecovery.max_rescue_level_attempted",
+                        Integer.toString(value));
+                return null;
+            }).when(() -> RescueParty.setMaxRescueLevelAttempted(anyInt()));
+
+        } catch (Exception e) {
+            // tests will fail, just printing the error
+            System.out.println("Error while mocking crashrecovery properties " + e.getMessage());
+        }
+
+        // mock properties in BootThreshold
+        try {
+            mSpyBootThreshold = spy(watchdog.new BootThreshold(
+                PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
+                PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS));
+            mCrashRecoveryPropertiesMap = new HashMap<>();
+
+            doAnswer((Answer<Integer>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.rescue_boot_count", "0");
+                return Integer.parseInt(storedValue);
+            }).when(mSpyBootThreshold).getCount();
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                int count = invocationOnMock.getArgument(0);
+                setCrashRecoveryPropRescueBootCount(count);
+                return null;
+            }).when(mSpyBootThreshold).setCount(anyInt());
+
+            doAnswer((Answer<Integer>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.boot_mitigation_count", "0");
+                return Integer.parseInt(storedValue);
+            }).when(mSpyBootThreshold).getMitigationCount();
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                int count = invocationOnMock.getArgument(0);
+                mCrashRecoveryPropertiesMap.put("crashrecovery.boot_mitigation_count",
+                        Integer.toString(count));
+                return null;
+            }).when(mSpyBootThreshold).setMitigationCount(anyInt());
+
+            doAnswer((Answer<Long>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.rescue_boot_start", "0");
+                return Long.parseLong(storedValue);
+            }).when(mSpyBootThreshold).getStart();
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                long count = invocationOnMock.getArgument(0);
+                mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_start",
+                        Long.toString(count));
+                return null;
+            }).when(mSpyBootThreshold).setStart(anyLong());
+
+            doAnswer((Answer<Long>) invocationOnMock -> {
+                String storedValue = mCrashRecoveryPropertiesMap
+                        .getOrDefault("crashrecovery.boot_mitigation_start", "0");
+                return Long.parseLong(storedValue);
+            }).when(mSpyBootThreshold).getMitigationStart();
+            doAnswer((Answer<Void>) invocationOnMock -> {
+                long count = invocationOnMock.getArgument(0);
+                mCrashRecoveryPropertiesMap.put("crashrecovery.boot_mitigation_start",
+                        Long.toString(count));
+                return null;
+            }).when(mSpyBootThreshold).setMitigationStart(anyLong());
+
+            Field mBootThresholdField = watchdog.getClass().getDeclaredField("mBootThreshold");
+            mBootThresholdField.setAccessible(true);
+            mBootThresholdField.set(watchdog, mSpyBootThreshold);
+        } catch (Exception e) {
+            // tests will fail, just printing the error
+            System.out.println("Error while spying BootThreshold " + e.getMessage());
+        }
+    }
+
+    private void setCrashRecoveryPropRescueBootCount(int count) {
+        mCrashRecoveryPropertiesMap.put("crashrecovery.rescue_boot_count",
+                Integer.toString(count));
+    }
+
+    private void setCrashRecoveryPropAttemptingReboot(boolean value) {
+        mCrashRecoveryPropertiesMap.put("crashrecovery.attempting_reboot",
+                Boolean.toString(value));
+    }
+
+    private void setCrashRecoveryPropLastFactoryReset(long value) {
+        mCrashRecoveryPropertiesMap.put("persist.crashrecovery.last_factory_reset",
+                Long.toString(value));
+    }
 }
diff --git a/services/tests/powerservicetests/Android.bp b/services/tests/powerservicetests/Android.bp
index 8d455fe..729dcbd 100644
--- a/services/tests/powerservicetests/Android.bp
+++ b/services/tests/powerservicetests/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_powermanager_framework",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["frameworks_base_license"],
 }
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 1de049e..51c9d0a 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_framework_backstage_power",
     // See: http://go/android-license-faq
     default_applicable_licenses: ["frameworks_base_license"],
 }
diff --git a/services/tests/powerstatstests/BstatsTestApp/Android.bp b/services/tests/powerstatstests/BstatsTestApp/Android.bp
index c82da9e..7408d13 100644
--- a/services/tests/powerstatstests/BstatsTestApp/Android.bp
+++ b/services/tests/powerstatstests/BstatsTestApp/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_framework_backstage_power",
     // 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"
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java
index 7c278ce..b322dd7 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java
@@ -18,22 +18,31 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.BrailleDisplayController;
+import android.content.Context;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.testing.DexmakerShareClassLoaderRule;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
 import com.google.common.truth.Expect;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.io.File;
 import java.nio.file.Path;
 import java.util.List;
 
@@ -54,6 +63,8 @@
     @Rule
     public final Expect expect = Expect.create();
 
+    private Context mContext;
+
     // To mock package-private class
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
@@ -62,7 +73,34 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mBrailleDisplayConnection = new BrailleDisplayConnection(new Object(), mServiceConnection);
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        when(mServiceConnection.isConnectedLocked()).thenReturn(true);
+        mBrailleDisplayConnection =
+                spy(new BrailleDisplayConnection(new Object(), mServiceConnection));
+    }
+
+    @Test
+    public void defaultNativeScanner_getHidrawNodePaths_returnsHidrawPaths() throws Exception {
+        File testDir = mContext.getFilesDir();
+        Path hidrawNode0 = Path.of(testDir.getPath(), "hidraw0");
+        Path hidrawNode1 = Path.of(testDir.getPath(), "hidraw1");
+        Path otherDevice = Path.of(testDir.getPath(), "otherDevice");
+        Path[] nodePaths = {hidrawNode0, hidrawNode1, otherDevice};
+        try {
+            for (Path node : nodePaths) {
+                assertThat(node.toFile().createNewFile()).isTrue();
+            }
+
+            BrailleDisplayConnection.BrailleDisplayScanner scanner =
+                    mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+
+            assertThat(scanner.getHidrawNodePaths(testDir.toPath()))
+                    .containsExactly(hidrawNode0, hidrawNode1);
+        } finally {
+            for (Path node : nodePaths) {
+                node.toFile().delete();
+            }
+        }
     }
 
     @Test
@@ -123,9 +161,38 @@
                 .isEqualTo(BrailleDisplayConnection.BUS_BLUETOOTH);
     }
 
+    @Test
+    public void write_bypassesServiceSideCheckWithLargeBuffer_disconnects() {
+        Mockito.doNothing().when(mBrailleDisplayConnection).disconnect();
+        mBrailleDisplayConnection.write(
+                new byte[IBinder.getSuggestedMaxIpcSizeBytes() * 2]);
+
+        verify(mBrailleDisplayConnection).disconnect();
+    }
+
+    @Test
+    public void write_notConnected_throwsIllegalStateException() {
+        when(mServiceConnection.isConnectedLocked()).thenReturn(false);
+
+        assertThrows(IllegalStateException.class,
+                () -> mBrailleDisplayConnection.write(new byte[1]));
+    }
+
+    @Test
+    public void write_unableToCreateWriteStream_disconnects() {
+        Mockito.doNothing().when(mBrailleDisplayConnection).disconnect();
+        // mBrailleDisplayConnection#connectLocked was never called so the
+        // connection's mHidrawNode is still null. This will throw an exception
+        // when attempting to create FileOutputStream on the node.
+        mBrailleDisplayConnection.write(new byte[1]);
+
+        verify(mBrailleDisplayConnection).disconnect();
+    }
+
     // BrailleDisplayConnection#setTestData() is used to enable CTS testing with
     // test Braille display data, but its own implementation should also be tested
     // so that issues in this helper don't cause confusing failures in CTS.
+
     @Test
     public void setTestData_scannerReturnsTestData() {
         Bundle bd1 = new Bundle(), bd2 = new Bundle();
@@ -148,7 +215,7 @@
         BrailleDisplayConnection.BrailleDisplayScanner scanner =
                 mBrailleDisplayConnection.setTestData(List.of(bd1, bd2));
 
-        expect.that(scanner.getHidrawNodePaths()).containsExactly(path1, path2);
+        expect.that(scanner.getHidrawNodePaths(Path.of("/dev"))).containsExactly(path1, path2);
         expect.that(scanner.getDeviceReportDescriptor(path1)).isEqualTo(desc1);
         expect.that(scanner.getDeviceReportDescriptor(path2)).isEqualTo(desc2);
         expect.that(scanner.getUniqueId(path1)).isEqualTo(uniq1);
@@ -156,4 +223,12 @@
         expect.that(scanner.getDeviceBusType(path1)).isEqualTo(bus1);
         expect.that(scanner.getDeviceBusType(path2)).isEqualTo(bus2);
     }
+
+    @Test
+    public void setTestData_emptyTestData_returnsNullNodePaths() {
+        BrailleDisplayConnection.BrailleDisplayScanner scanner =
+                mBrailleDisplayConnection.setTestData(List.of());
+
+        expect.that(scanner.getHidrawNodePaths(Path.of("/dev"))).isNull();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 4307ec5..cea10ea 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -87,6 +87,7 @@
 import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManagerInternal;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -1223,6 +1224,7 @@
         private final UserManagerInternal mUserManagerInternalMock;
         private final WindowManagerService mWindowManagerMock;
         private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+        private final PowerManagerInternal mPowerManagerInternal;
         private final KeyguardManager mKeyguardManagerMock;
         private final LockPatternUtils mLockPatternUtilsMock;
 
@@ -1244,6 +1246,7 @@
             mWindowManagerMock = mock(WindowManagerService.class);
             mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
             mStorageManagerMock = mock(IStorageManager.class);
+            mPowerManagerInternal = mock(PowerManagerInternal.class);
             mKeyguardManagerMock = mock(KeyguardManager.class);
             when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true);
             mLockPatternUtilsMock = mock(LockPatternUtils.class);
@@ -1309,6 +1312,11 @@
         }
 
         @Override
+        PowerManagerInternal getPowerManagerInternal() {
+            return mPowerManagerInternal;
+        }
+
+        @Override
         KeyguardManager getKeyguardManager() {
             return mKeyguardManagerMock;
         }
diff --git a/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
index fc5819d..e756082 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
@@ -69,6 +69,7 @@
     private AudioSystemAdapter mSpyAudioSystem;
     private SystemServerAdapter mSystemServer;
     private SettingsAdapter mSettingsAdapter;
+    private AudioVolumeGroupHelperBase mAudioVolumeGroupHelper;
     private TestLooper mTestLooper;
 
     private AudioService mAudioService;
@@ -93,9 +94,11 @@
         mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
         mSystemServer = new NoOpSystemServerAdapter();
         mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioVolumeGroupHelper = new AudioVolumeGroupHelperBase();
 
         mAudioService = new AudioService(mContext, mSpyAudioSystem, mSystemServer,
-                mSettingsAdapter, mMockAudioPolicy, mTestLooper.getLooper()) {
+                mSettingsAdapter, mAudioVolumeGroupHelper, mMockAudioPolicy,
+                mTestLooper.getLooper()) {
             @Override
             public int getDeviceForStream(int stream) {
                 return AudioSystem.DEVICE_OUT_SPEAKER;
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
index d4d3128..3623012 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
@@ -56,6 +56,7 @@
     private AudioSystemAdapter mSpyAudioSystem;
     private SystemServerAdapter mSystemServer;
     private SettingsAdapter mSettingsAdapter;
+    private AudioVolumeGroupHelperBase mAudioVolumeGroupHelper;
     private TestLooper mTestLooper;
     private AudioPolicyFacade mAudioPolicyMock = mock(AudioPolicyFacade.class);
 
@@ -71,8 +72,10 @@
 
         mSystemServer = new NoOpSystemServerAdapter();
         mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioVolumeGroupHelper = new AudioVolumeGroupHelperBase();
         mAudioService = new AudioService(mContext, mSpyAudioSystem, mSystemServer,
-                mSettingsAdapter, mAudioPolicyMock, mTestLooper.getLooper()) {
+                mSettingsAdapter, mAudioVolumeGroupHelper, mAudioPolicyMock,
+                mTestLooper.getLooper()) {
             @Override
             public int getDeviceForStream(int stream) {
                 return AudioSystem.DEVICE_OUT_SPEAKER;
@@ -82,8 +85,9 @@
         mTestLooper.dispatchAll();
     }
 
+    // ------------ AudioDeviceVolumeManager related tests ------------
     @Test
-    public void testSetDeviceVolume() {
+    public void setDeviceVolume_checkIndex() {
         AudioManager am = mContext.getSystemService(AudioManager.class);
         final int minIndex = am.getStreamMinVolume(AudioManager.STREAM_MUSIC);
         final int maxIndex = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
@@ -110,7 +114,7 @@
 
     @Test
     @RequiresFlagsDisabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
-    public void testConfigurablePreScaleAbsoluteVolume() throws Exception {
+    public void configurablePreScaleAbsoluteVolume_checkIndex() throws Exception {
         AudioManager am = mContext.getSystemService(AudioManager.class);
         final int minIndex = am.getStreamMinVolume(AudioManager.STREAM_MUSIC);
         final int maxIndex = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
@@ -159,7 +163,7 @@
 
     @Test
     @RequiresFlagsEnabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
-    public void testDisablePreScaleAbsoluteVolume() throws Exception {
+    public void disablePreScaleAbsoluteVolume_checkIndex() throws Exception {
         AudioManager am = mContext.getSystemService(AudioManager.class);
         final int minIndex = am.getStreamMinVolume(AudioManager.STREAM_MUSIC);
         final int maxIndex = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
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 e565faa..634877e 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java
@@ -60,6 +60,7 @@
     private Context mContext;
     private AudioSystemAdapter mSpyAudioSystem;
     private SettingsAdapter mSettingsAdapter;
+    private AudioVolumeGroupHelperBase mAudioVolumeGroupHelper;
 
     @Spy private NoOpSystemServerAdapter mSpySystemServer;
     @Mock private AppOpsManager mMockAppOpsManager;
@@ -80,11 +81,12 @@
         mContext = InstrumentationRegistry.getTargetContext();
         mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
         mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioVolumeGroupHelper = new AudioVolumeGroupHelperBase();
         when(mMockAppOpsManager.noteOp(anyInt(), anyInt(), anyString(), anyString(), anyString()))
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         mAudioService = new AudioService(mContext, mSpyAudioSystem, mSpySystemServer,
-                mSettingsAdapter, mMockAudioPolicy, null, mMockAppOpsManager,
-                mMockPermissionEnforcer);
+                mSettingsAdapter, mAudioVolumeGroupHelper, mMockAudioPolicy, null,
+                mMockAppOpsManager, mMockPermissionEnforcer);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java
index f5862ac..8dfcc18 100644
--- a/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/DeviceVolumeBehaviorTest.java
@@ -50,6 +50,7 @@
     private AudioSystemAdapter mAudioSystem;
     private SystemServerAdapter mSystemServer;
     private SettingsAdapter mSettingsAdapter;
+    private AudioVolumeGroupHelperBase mAudioVolumeGroupHelper;
     private TestLooper mTestLooper;
     private AudioPolicyFacade mAudioPolicyMock = mock(AudioPolicyFacade.class);
 
@@ -71,8 +72,10 @@
         mAudioSystem = new NoOpAudioSystemAdapter();
         mSystemServer = new NoOpSystemServerAdapter();
         mSettingsAdapter = new NoOpSettingsAdapter();
+        mAudioVolumeGroupHelper = new AudioVolumeGroupHelperBase();
         mAudioService = new AudioService(mContext, mAudioSystem, mSystemServer,
-                mSettingsAdapter, mAudioPolicyMock, mTestLooper.getLooper());
+                mSettingsAdapter, mAudioVolumeGroupHelper, mAudioPolicyMock,
+                mTestLooper.getLooper());
         mTestLooper.dispatchAll();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 0eac718..96ac5d2 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -137,6 +137,11 @@
     }
 
     @Override
+    public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, int device) {
+        return AudioSystem.AUDIO_STATUS_OK;
+    }
+
+    @Override
     @NonNull
     public ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
             @NonNull AudioAttributes attributes, boolean forVolume) {
diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
new file mode 100644
index 0000000..83bbd0e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
@@ -0,0 +1,726 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.audio;
+
+import static android.media.AudioManager.ADJUST_LOWER;
+import static android.media.AudioManager.ADJUST_MUTE;
+import static android.media.AudioManager.ADJUST_RAISE;
+import static android.media.AudioManager.DEVICE_OUT_BLE_SPEAKER;
+import static android.media.AudioManager.DEVICE_OUT_BLUETOOTH_SCO;
+import static android.media.AudioManager.DEVICE_OUT_SPEAKER;
+import static android.media.AudioManager.DEVICE_OUT_USB_DEVICE;
+import static android.media.AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET;
+import static android.media.AudioManager.FLAG_ALLOW_RINGER_MODES;
+import static android.media.AudioManager.FLAG_BLUETOOTH_ABS_VOLUME;
+import static android.media.AudioManager.RINGER_MODE_NORMAL;
+import static android.media.AudioManager.RINGER_MODE_VIBRATE;
+import static android.media.AudioManager.STREAM_ACCESSIBILITY;
+import static android.media.AudioManager.STREAM_ALARM;
+import static android.media.AudioManager.STREAM_BLUETOOTH_SCO;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioManager.STREAM_NOTIFICATION;
+import static android.media.AudioManager.STREAM_RING;
+import static android.media.AudioManager.STREAM_SYSTEM;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
+
+import static com.android.media.audio.Flags.FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+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 static org.junit.Assume.assumeNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IDeviceVolumeBehaviorDispatcher;
+import android.media.VolumeInfo;
+import android.media.audiopolicy.AudioVolumeGroup;
+import android.os.Looper;
+import android.os.PermissionEnforcer;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class VolumeHelperTest {
+    private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
+            AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    private MyAudioService mAudioService;
+
+    private AudioManager mAm;
+
+    private Context mContext;
+
+    private AudioSystemAdapter mSpyAudioSystem;
+    private SettingsAdapter mSettingsAdapter;
+    @Spy
+    private NoOpSystemServerAdapter mSpySystemServer;
+    @Mock
+    private AppOpsManager mMockAppOpsManager;
+    @Mock
+    private PermissionEnforcer mMockPermissionEnforcer;
+    @Mock
+    private AudioVolumeGroupHelperBase mAudioVolumeGroupHelper;
+
+    private final AudioPolicyFacade mFakeAudioPolicy = lookbackAudio -> false;
+
+    private AudioVolumeGroup mAudioMusicVolumeGroup;
+
+    private TestLooper mTestLooper;
+
+    public static final int[] BASIC_VOLUME_BEHAVIORS = {
+            AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
+            AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
+            AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED
+    };
+
+    private static class MyAudioService extends AudioService {
+        private final SparseIntArray mStreamDevice = new SparseIntArray();
+
+        MyAudioService(Context context, AudioSystemAdapter audioSystem,
+                SystemServerAdapter systemServer, SettingsAdapter settings,
+                AudioVolumeGroupHelperBase audioVolumeGroupHelper, AudioPolicyFacade audioPolicy,
+                @Nullable Looper looper, AppOpsManager appOps,
+                @NonNull PermissionEnforcer enforcer) {
+            super(context, audioSystem, systemServer, settings, audioVolumeGroupHelper,
+                    audioPolicy, looper, appOps, enforcer);
+        }
+
+        public void setDeviceForStream(int stream, int device) {
+            mStreamDevice.put(stream, device);
+        }
+
+        @Override
+        public int getDeviceForStream(int stream) {
+            if (mStreamDevice.indexOfKey(stream) < 0) {
+                return DEVICE_OUT_SPEAKER;
+            }
+            return mStreamDevice.get(stream);
+        }
+    }
+
+    private static class TestDeviceVolumeBehaviorDispatcherStub
+            extends IDeviceVolumeBehaviorDispatcher.Stub {
+
+        private AudioDeviceAttributes mDevice;
+        private int mVolumeBehavior;
+        private int mTimesCalled;
+
+        @Override
+        public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
+                @AudioManager.DeviceVolumeBehavior int volumeBehavior) {
+            mDevice = device;
+            mVolumeBehavior = volumeBehavior;
+            mTimesCalled++;
+        }
+
+        public void reset() {
+            mTimesCalled = 0;
+            mVolumeBehavior = DEVICE_VOLUME_BEHAVIOR_UNSET;
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mTestLooper = new TestLooper();
+
+        mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
+        mSettingsAdapter = new NoOpSettingsAdapter();
+
+        mAudioMusicVolumeGroup = getStreamTypeVolumeGroup(STREAM_MUSIC);
+        if (mAudioMusicVolumeGroup != null) {
+            when(mAudioVolumeGroupHelper.getAudioVolumeGroups()).thenReturn(
+                    List.of(mAudioMusicVolumeGroup));
+        }
+
+        mAm = mContext.getSystemService(AudioManager.class);
+
+        mAudioService = new MyAudioService(mContext, mSpyAudioSystem, mSpySystemServer,
+                mSettingsAdapter, mAudioVolumeGroupHelper, mFakeAudioPolicy,
+                mTestLooper.getLooper(), mMockAppOpsManager, mMockPermissionEnforcer);
+
+        mTestLooper.dispatchAll();
+        prepareAudioServiceState();
+        mTestLooper.dispatchAll();
+
+        reset(mSpyAudioSystem);
+
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
+                        Manifest.permission.MODIFY_AUDIO_ROUTING,
+                        Manifest.permission.MODIFY_PHONE_STATE,
+                        android.Manifest.permission.STATUS_BAR_SERVICE);
+    }
+
+    private void prepareAudioServiceState() throws Exception {
+        int[] usedStreamTypes =
+                {STREAM_MUSIC, STREAM_NOTIFICATION, STREAM_RING, STREAM_ALARM, STREAM_SYSTEM,
+                        STREAM_VOICE_CALL, STREAM_ACCESSIBILITY};
+        for (int streamType : usedStreamTypes) {
+            final int streamVolume = (mAm.getStreamMinVolume(streamType) + mAm.getStreamMaxVolume(
+                    streamType)) / 2;
+
+            mAudioService.setStreamVolume(streamType, streamVolume, /*flags=*/0,
+                    mContext.getOpPackageName());
+        }
+
+        mAudioService.setRingerModeInternal(RINGER_MODE_NORMAL, mContext.getOpPackageName());
+        mAudioService.setRingerModeExternal(RINGER_MODE_NORMAL, mContext.getOpPackageName());
+    }
+
+    private AudioVolumeGroup getStreamTypeVolumeGroup(int streamType) {
+        // get the volume group from the AudioManager to pass permission checks
+        // when requesting from real service
+        final List<AudioVolumeGroup> audioVolumeGroups = AudioManager.getAudioVolumeGroups();
+        for (AudioVolumeGroup vg : audioVolumeGroups) {
+            for (int stream : vg.getLegacyStreamTypes()) {
+                if (stream == streamType) {
+                    return vg;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @After
+    public void tearDown() {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    // --------------- Volume Stream APIs ---------------
+    @Test
+    public void setStreamVolume_callsASSetStreamVolumeIndex() throws Exception {
+        int newIndex = circularNoMinMaxIncrementVolume(STREAM_MUSIC);
+
+        mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
+        mAudioService.setStreamVolume(STREAM_MUSIC, newIndex, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem).setStreamVolumeIndexAS(
+                eq(STREAM_MUSIC), eq(newIndex), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    @Test
+    public void setStreamRingVolume0_setsRingerModeVibrate() throws Exception {
+        mAudioService.setStreamVolume(STREAM_RING, 0, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        assertEquals(RINGER_MODE_VIBRATE, mAudioService.getRingerModeExternal());
+    }
+
+    @Test
+    public void adjustStreamVolume_callsASSetStreamVolumeIndex() throws Exception {
+        mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
+        mAudioService.adjustStreamVolume(STREAM_MUSIC, ADJUST_LOWER, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                eq(STREAM_MUSIC), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    @Test
+    public void handleVolumeKey_callsASSetStreamVolumeIndex() throws Exception {
+        final KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
+
+        mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
+        mAudioService.handleVolumeKey(keyEvent, /*isOnTv=*/false, mContext.getOpPackageName(),
+                "adjustSuggestedStreamVolume_callsAudioSystemSetStreamVolumeIndex");
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem).setStreamVolumeIndexAS(
+                eq(STREAM_MUSIC), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    // --------------- Volume Group APIs ---------------
+
+    @Test
+    public void setVolumeGroupVolumeIndex_callsASSetVolumeIndexForAttributes() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
+        mAudioService.setVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId(),
+                circularNoMinMaxIncrementVolume(STREAM_MUSIC), /*flags=*/0,
+                mContext.getOpPackageName(),  /*attributionTag*/null);
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem).setVolumeIndexForAttributes(
+                any(), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    @Test
+    public void adjustVolumeGroupVolume_callsASSetVolumeIndexForAttributes() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
+        mAudioService.adjustVolumeGroupVolume(mAudioMusicVolumeGroup.getId(),
+                ADJUST_LOWER, /*flags=*/0, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem).setVolumeIndexForAttributes(
+                any(), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    @Test
+    public void check_getVolumeGroupVolumeIndex() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        int newIndex = circularNoMinMaxIncrementVolume(STREAM_MUSIC);
+
+        mAudioService.setVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId(),
+                newIndex, /*flags=*/0, mContext.getOpPackageName(),  /*attributionTag*/null);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mAudioService.getVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId()),
+                newIndex);
+        assertEquals(mAudioService.getStreamVolume(STREAM_MUSIC),
+                newIndex);
+    }
+
+    @Test
+    public void check_getVolumeGroupMaxVolumeIndex() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        assertEquals(mAudioService.getVolumeGroupMaxVolumeIndex(mAudioMusicVolumeGroup.getId()),
+                mAudioService.getStreamMaxVolume(STREAM_MUSIC));
+    }
+
+    @Test
+    public void check_getVolumeGroupMinVolumeIndex() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        assertEquals(mAudioService.getVolumeGroupMinVolumeIndex(mAudioMusicVolumeGroup.getId()),
+                mAudioService.getStreamMinVolume(STREAM_MUSIC));
+    }
+
+    @Test
+    public void check_getLastAudibleVolumeForVolumeGroup() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        assertEquals(
+                mAudioService.getLastAudibleVolumeForVolumeGroup(mAudioMusicVolumeGroup.getId()),
+                mAudioService.getLastAudibleStreamVolume(STREAM_MUSIC));
+    }
+
+    @Test
+    public void check_isVolumeGroupMuted() throws Exception {
+        assumeNotNull(mAudioMusicVolumeGroup);
+
+        assertEquals(mAudioService.isVolumeGroupMuted(mAudioMusicVolumeGroup.getId()),
+                mAudioService.isStreamMute(STREAM_MUSIC));
+    }
+
+    // ------------------------- Mute Tests ------------------------
+
+    @Test
+    public void check_setMasterMute() {
+        mAudioService.setMasterMute(true, /*flags=*/0, mContext.getOpPackageName(),
+                mContext.getUserId(), /*attributionTag*/"");
+
+        assertTrue(mAudioService.isMasterMute());
+    }
+
+    @Test
+    public void check_isStreamAffectedByMute() {
+        assertFalse(mAudioService.isStreamAffectedByMute(STREAM_VOICE_CALL));
+    }
+
+    // --------------------- Volume Flag Check --------------------
+
+    @Test
+    public void flagAbsVolume_onBtDevice_changesVolume() throws Exception {
+        mAudioService.setDeviceForStream(STREAM_NOTIFICATION, DEVICE_OUT_BLE_SPEAKER);
+
+        int newIndex = circularNoMinMaxIncrementVolume(STREAM_NOTIFICATION);
+        mAudioService.setStreamVolume(STREAM_NOTIFICATION, newIndex, FLAG_BLUETOOTH_ABS_VOLUME,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        verify(mSpyAudioSystem).setStreamVolumeIndexAS(
+                eq(STREAM_NOTIFICATION), anyInt(), eq(DEVICE_OUT_BLE_SPEAKER));
+
+        reset(mSpyAudioSystem);
+        mAudioService.adjustStreamVolume(STREAM_NOTIFICATION, ADJUST_LOWER,
+                FLAG_BLUETOOTH_ABS_VOLUME, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        verify(mSpyAudioSystem).setStreamVolumeIndexAS(
+                eq(STREAM_NOTIFICATION), anyInt(), eq(DEVICE_OUT_BLE_SPEAKER));
+    }
+
+    @Test
+    public void flagAbsVolume_onNonBtDevice_noVolumeChange() throws Exception {
+        mAudioService.setDeviceForStream(STREAM_NOTIFICATION, DEVICE_OUT_SPEAKER);
+
+        int newIndex = circularNoMinMaxIncrementVolume(STREAM_NOTIFICATION);
+        mAudioService.setStreamVolume(STREAM_NOTIFICATION, newIndex, FLAG_BLUETOOTH_ABS_VOLUME,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
+                eq(STREAM_NOTIFICATION), eq(newIndex), eq(DEVICE_OUT_BLE_SPEAKER));
+
+        mAudioService.adjustStreamVolume(STREAM_NOTIFICATION, ADJUST_LOWER,
+                FLAG_BLUETOOTH_ABS_VOLUME, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
+                eq(STREAM_NOTIFICATION), anyInt(), eq(DEVICE_OUT_BLE_SPEAKER));
+    }
+
+    @Test
+    public void flagAllowRingerModes_onSystemStreams_changesMode() throws Exception {
+        mAudioService.setStreamVolume(STREAM_SYSTEM,
+                mAudioService.getStreamMinVolume(STREAM_SYSTEM), /*flags=*/0,
+                mContext.getOpPackageName());
+        mAudioService.setRingerModeInternal(RINGER_MODE_VIBRATE, mContext.getOpPackageName());
+
+        mAudioService.adjustStreamVolume(STREAM_SYSTEM, ADJUST_RAISE, FLAG_ALLOW_RINGER_MODES,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        assertNotEquals(mAudioService.getRingerModeInternal(), RINGER_MODE_VIBRATE);
+    }
+
+    @Test
+    public void flagAllowRingerModesAbsent_onNonSystemStreams_noModeChange() throws Exception {
+        mAudioService.setStreamVolume(STREAM_MUSIC,
+                mAudioService.getStreamMinVolume(STREAM_MUSIC), /*flags=*/0,
+                mContext.getOpPackageName());
+        mAudioService.setRingerModeInternal(RINGER_MODE_VIBRATE, mContext.getOpPackageName());
+
+        mAudioService.adjustStreamVolume(STREAM_MUSIC, ADJUST_RAISE, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        assertEquals(mAudioService.getRingerModeInternal(), RINGER_MODE_VIBRATE);
+    }
+
+    // --------------------- Permission tests ---------------------
+
+    @Test
+    public void appOpsIgnore_noVolumeChange() throws Exception {
+        reset(mMockAppOpsManager);
+        when(mMockAppOpsManager.noteOp(anyInt(), anyInt(), anyString(), isNull(), isNull()))
+                .thenReturn(AppOpsManager.MODE_IGNORED);
+
+        mAudioService.adjustStreamVolume(STREAM_MUSIC, ADJUST_LOWER, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
+                eq(STREAM_MUSIC), anyInt(), anyInt());
+    }
+
+    @Test
+    public void modifyPhoneStateAbsent_noMuteVoiceCallScoAllowed() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+
+        mAudioService.setDeviceForStream(STREAM_VOICE_CALL, DEVICE_OUT_USB_DEVICE);
+        mAudioService.adjustStreamVolume(STREAM_VOICE_CALL, ADJUST_MUTE, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
+                eq(STREAM_VOICE_CALL), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+
+        mAudioService.setDeviceForStream(STREAM_BLUETOOTH_SCO, DEVICE_OUT_BLUETOOTH_SCO);
+        mAudioService.adjustStreamVolume(STREAM_BLUETOOTH_SCO, ADJUST_MUTE, /*flags=*/0,
+                mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem, times(0)).setStreamVolumeIndexAS(
+                eq(STREAM_BLUETOOTH_SCO), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+    }
+
+    // ----------------- AudioDeviceVolumeManager -----------------
+    @Test
+    public void setDeviceVolume_checkIndex() {
+        final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
+        final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);
+        final int midIndex = (minIndex + maxIndex) / 2;
+        final VolumeInfo volMedia = new VolumeInfo.Builder(STREAM_MUSIC)
+                .setMinVolumeIndex(minIndex)
+                .setMaxVolumeIndex(maxIndex)
+                .build();
+        final VolumeInfo volMin = new VolumeInfo.Builder(volMedia).setVolumeIndex(minIndex).build();
+        final VolumeInfo volMid = new VolumeInfo.Builder(volMedia).setVolumeIndex(midIndex).build();
+        final AudioDeviceAttributes usbDevice = new AudioDeviceAttributes(
+                /*native type*/ AudioSystem.DEVICE_OUT_USB_DEVICE, /*address*/ "bla");
+
+        mAudioService.setDeviceVolume(volMin, usbDevice, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        assertEquals(mAudioService.getDeviceVolume(volMin, usbDevice,
+                mContext.getOpPackageName()), volMin);
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                STREAM_MUSIC, minIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
+
+        mAudioService.setDeviceVolume(volMid, usbDevice, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        assertEquals(mAudioService.getDeviceVolume(volMid, usbDevice,
+                mContext.getOpPackageName()), volMid);
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                STREAM_MUSIC, midIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
+    public void configurablePreScaleAbsoluteVolume_checkIndex() throws Exception {
+        final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
+        final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);
+        final VolumeInfo volMedia = new VolumeInfo.Builder(STREAM_MUSIC)
+                .setMinVolumeIndex(minIndex)
+                .setMaxVolumeIndex(maxIndex)
+                .build();
+        final AudioDeviceAttributes bleDevice = new AudioDeviceAttributes(
+                /*native type*/ AudioSystem.DEVICE_OUT_BLE_HEADSET, /*address*/ "fake_ble");
+        final int maxPreScaleIndex = 3;
+        final float[] preScale = new float[maxPreScaleIndex];
+        preScale[0] = mContext.getResources().getFraction(
+                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index1,
+                1, 1);
+        preScale[1] = mContext.getResources().getFraction(
+                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index2,
+                1, 1);
+        preScale[2] = mContext.getResources().getFraction(
+                com.android.internal.R.fraction.config_prescaleAbsoluteVolume_index3,
+                1, 1);
+
+        for (int i = 0; i < maxPreScaleIndex; i++) {
+            final int targetIndex = (int) (preScale[i] * maxIndex);
+            final VolumeInfo volCur = new VolumeInfo.Builder(volMedia)
+                    .setVolumeIndex(i + 1).build();
+            // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:1~3)
+            mAudioService.setDeviceVolume(volCur, bleDevice, mContext.getOpPackageName());
+            mTestLooper.dispatchAll();
+
+            assertEquals(
+                    mAudioService.getDeviceVolume(volCur, bleDevice, mContext.getOpPackageName()),
+                    volCur);
+            // Stream volume changes
+            verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                    STREAM_MUSIC, targetIndex,
+                    AudioSystem.DEVICE_OUT_BLE_HEADSET);
+        }
+
+        // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
+        final VolumeInfo volIndex4 = new VolumeInfo.Builder(volMedia)
+                .setVolumeIndex(4).build();
+        mAudioService.setDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        assertEquals(
+                mAudioService.getDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName()),
+                volIndex4);
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                STREAM_MUSIC, maxIndex,
+                AudioSystem.DEVICE_OUT_BLE_HEADSET);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
+    public void disablePreScaleAbsoluteVolume_checkIndex() throws Exception {
+        final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
+        final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);
+        final VolumeInfo volMedia = new VolumeInfo.Builder(STREAM_MUSIC)
+                .setMinVolumeIndex(minIndex)
+                .setMaxVolumeIndex(maxIndex)
+                .build();
+        final AudioDeviceAttributes bleDevice = new AudioDeviceAttributes(
+                /*native type*/ AudioSystem.DEVICE_OUT_BLE_HEADSET, /*address*/ "bla");
+        final int maxPreScaleIndex = 3;
+
+        for (int i = 0; i < maxPreScaleIndex; i++) {
+            final VolumeInfo volCur = new VolumeInfo.Builder(volMedia)
+                    .setVolumeIndex(i + 1).build();
+            // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:1~3)
+            mAudioService.setDeviceVolume(volCur, bleDevice, mContext.getOpPackageName());
+            mTestLooper.dispatchAll();
+
+            // Stream volume changes
+            verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                    STREAM_MUSIC, maxIndex,
+                    AudioSystem.DEVICE_OUT_BLE_HEADSET);
+        }
+
+        // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set (index:4)
+        final VolumeInfo volIndex4 = new VolumeInfo.Builder(volMedia)
+                .setVolumeIndex(4).build();
+        mAudioService.setDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
+                STREAM_MUSIC, maxIndex,
+                AudioSystem.DEVICE_OUT_BLE_HEADSET);
+    }
+
+    // ---------------- DeviceVolumeBehaviorTest ----------------
+    @Test
+    public void setDeviceVolumeBehavior_changesDeviceVolumeBehavior() {
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        for (int behavior : BASIC_VOLUME_BEHAVIORS) {
+            mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, behavior,
+                    mContext.getOpPackageName());
+            mTestLooper.dispatchAll();
+
+            int actualBehavior = mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT);
+
+            assertWithMessage("Expected volume behavior to be " + behavior
+                    + " but was instead " + actualBehavior)
+                    .that(actualBehavior).isEqualTo(behavior);
+        }
+    }
+
+    @Test
+    public void setToNewBehavior_triggersDeviceVolumeBehaviorDispatcher() {
+        TestDeviceVolumeBehaviorDispatcherStub dispatcher =
+                new TestDeviceVolumeBehaviorDispatcherStub();
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        for (int behavior : BASIC_VOLUME_BEHAVIORS) {
+            dispatcher.reset();
+            mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, behavior,
+                    mContext.getOpPackageName());
+            mTestLooper.dispatchAll();
+
+            assertThat(dispatcher.mTimesCalled).isEqualTo(1);
+            assertThat(dispatcher.mDevice).isEqualTo(DEVICE_SPEAKER_OUT);
+            assertWithMessage("Expected dispatched volume behavior to be " + behavior
+                    + " but was instead " + dispatcher.mVolumeBehavior)
+                    .that(dispatcher.mVolumeBehavior).isEqualTo(behavior);
+        }
+    }
+
+    @Test
+    public void setToSameBehavior_doesNotTriggerDeviceVolumeBehaviorDispatcher() {
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        TestDeviceVolumeBehaviorDispatcherStub dispatcher =
+                new TestDeviceVolumeBehaviorDispatcherStub();
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        assertThat(dispatcher.mTimesCalled).isEqualTo(0);
+    }
+
+    @Test
+    public void unregisterDeviceVolumeBehaviorDispatcher_noLongerTriggered() {
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+
+        TestDeviceVolumeBehaviorDispatcherStub dispatcher =
+                new TestDeviceVolumeBehaviorDispatcherStub();
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
+        mAudioService.registerDeviceVolumeBehaviorDispatcher(false, dispatcher);
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL, mContext.getOpPackageName());
+        mTestLooper.dispatchAll();
+        assertThat(dispatcher.mTimesCalled).isEqualTo(0);
+    }
+
+    @Test
+    public void setDeviceVolumeBehavior_checkIsVolumeFixed() throws Exception {
+        when(mSpyAudioSystem.getDevicesForAttributes(any(), anyBoolean())).thenReturn(
+                new ArrayList<>(List.of(DEVICE_SPEAKER_OUT)));
+
+        mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+                AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, mContext.getOpPackageName());
+
+        assertTrue(mAudioService.isVolumeFixed());
+    }
+
+    private int circularNoMinMaxIncrementVolume(int streamType) throws Exception {
+        final int streamMinVolume = mAm.getStreamMinVolume(streamType) + 1;
+        final int streamMaxVolume = mAm.getStreamMaxVolume(streamType) - 1;
+
+        int streamVolume = mAudioService.getStreamVolume(streamType);
+        if (streamVolume + 1 > streamMaxVolume) {
+            return streamMinVolume;
+        }
+        return streamVolume + 1;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
index 132b621..ec3e97b 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
@@ -38,6 +38,7 @@
 import android.app.WindowConfiguration;
 import android.companion.virtual.IVirtualDeviceIntentInterceptor;
 import android.companion.virtual.VirtualDeviceManager;
+import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -712,6 +713,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
@@ -732,6 +734,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
@@ -753,6 +756,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
@@ -774,6 +778,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ Collections.singleton(blockedComponent),
@@ -795,6 +800,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ false,
                 /* activityPolicyExemptions= */ Collections.singleton(allowedComponent),
@@ -816,6 +822,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
@@ -837,6 +844,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
@@ -858,6 +866,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
@@ -880,6 +889,7 @@
         return new GenericWindowPolicyController(
                 0,
                 0,
+                AttributionSource.myAttributionSource(),
                 /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
                 /* activityLaunchAllowedByDefault= */ true,
                 /* activityPolicyExemptions= */ new ArraySet<>(),
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
index 07e6ab2..fd880dd 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 
+import android.content.AttributionSource;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.IInputManager;
 import android.hardware.input.InputManagerGlobal;
@@ -95,6 +96,7 @@
         mInputController = new InputController(mNativeWrapperMock,
                 new Handler(TestableLooper.get(this).getLooper()),
                 InstrumentationRegistry.getTargetContext().getSystemService(WindowManager.class),
+                AttributionSource.myAttributionSource(),
                 threadVerifier);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
index faece4f..67fc564 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
@@ -32,6 +32,7 @@
 import android.companion.virtual.sensor.VirtualSensor;
 import android.companion.virtual.sensor.VirtualSensorConfig;
 import android.companion.virtual.sensor.VirtualSensorEvent;
+import android.content.AttributionSource;
 import android.hardware.Sensor;
 import android.os.Binder;
 import android.os.IBinder;
@@ -96,6 +97,7 @@
         Throwable thrown = assertThrows(
                 RuntimeException.class,
                 () -> new SensorController(mVirtualDevice, VIRTUAL_DEVICE_ID,
+                        AttributionSource.myAttributionSource(),
                         mVirtualSensorCallback, List.of(mVirtualSensorConfig)));
 
         assertThat(thrown.getCause().getMessage())
@@ -168,6 +170,7 @@
         doReturn(VIRTUAL_DEVICE_ID).when(mVirtualDevice).getDeviceId();
 
         SensorController sensorController = new SensorController(mVirtualDevice, VIRTUAL_DEVICE_ID,
+                AttributionSource.myAttributionSource(),
                 mVirtualSensorCallback, List.of(mVirtualSensorConfig));
 
         List<VirtualSensor> sensors = sensorController.getSensorList();
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 157e893..5e0806d 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -389,7 +389,8 @@
         final InputController.DeviceCreationThreadVerifier threadVerifier = () -> true;
         mInputController = new InputController(mNativeWrapperMock,
                 new Handler(TestableLooper.get(this).getLooper()),
-                mContext.getSystemService(WindowManager.class), threadVerifier);
+                mContext.getSystemService(WindowManager.class),
+                AttributionSource.myAttributionSource(), threadVerifier);
         mCameraAccessController =
                 new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
 
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index ef5270e..52f28b9 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -27,6 +27,7 @@
 
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.content.AttributionSource;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.media.AudioPlaybackConfiguration;
@@ -72,11 +73,13 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
-        mVirtualAudioController = new VirtualAudioController(mContext);
+        mVirtualAudioController = new VirtualAudioController(mContext,
+                AttributionSource.myAttributionSource());
         mGenericWindowPolicyController =
                 new GenericWindowPolicyController(
                         FLAG_SECURE,
                         SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+                        AttributionSource.myAttributionSource(),
                         /* allowedUsers= */ new ArraySet<>(),
                         /* activityLaunchAllowedByDefault= */ true,
                         /* activityPolicyExemptions= */ new ArraySet<>(),
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
index 81981e6..9ca1df0 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/camera/VirtualCameraControllerTest.java
@@ -37,6 +37,7 @@
 import android.companion.virtual.camera.VirtualCameraConfig;
 import android.companion.virtualcamera.IVirtualCameraService;
 import android.companion.virtualcamera.VirtualCameraConfiguration;
+import android.content.AttributionSource;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
@@ -104,7 +105,7 @@
     public void registerCamera_registersCamera(int lensFacing) throws Exception {
         mVirtualCameraController.registerCamera(createVirtualCameraConfig(
                 CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1, CAMERA_NAME_1,
-                CAMERA_SENSOR_ORIENTATION_1, lensFacing));
+                CAMERA_SENSOR_ORIENTATION_1, lensFacing), AttributionSource.myAttributionSource());
 
         ArgumentCaptor<VirtualCameraConfiguration> configurationCaptor =
                 ArgumentCaptor.forClass(VirtualCameraConfiguration.class);
@@ -121,7 +122,7 @@
         VirtualCameraConfig config = createVirtualCameraConfig(
                 CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1, CAMERA_NAME_1,
                 CAMERA_SENSOR_ORIENTATION_1, CAMERA_LENS_FACING_1);
-        mVirtualCameraController.registerCamera(config);
+        mVirtualCameraController.registerCamera(config, AttributionSource.myAttributionSource());
 
         mVirtualCameraController.unregisterCamera(config);
 
@@ -131,11 +132,15 @@
     @Test
     public void close_unregistersAllCameras() throws Exception {
         mVirtualCameraController.registerCamera(createVirtualCameraConfig(
-                CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1, CAMERA_NAME_1,
-                CAMERA_SENSOR_ORIENTATION_1, CAMERA_LENS_FACING_1));
+                        CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1,
+                        CAMERA_NAME_1,
+                        CAMERA_SENSOR_ORIENTATION_1, CAMERA_LENS_FACING_1),
+                AttributionSource.myAttributionSource());
         mVirtualCameraController.registerCamera(createVirtualCameraConfig(
-                CAMERA_WIDTH_2, CAMERA_HEIGHT_2, CAMERA_FORMAT_2, CAMERA_MAX_FPS_2, CAMERA_NAME_2,
-                CAMERA_SENSOR_ORIENTATION_2, CAMERA_LENS_FACING_2));
+                        CAMERA_WIDTH_2, CAMERA_HEIGHT_2, CAMERA_FORMAT_2, CAMERA_MAX_FPS_2,
+                        CAMERA_NAME_2,
+                        CAMERA_SENSOR_ORIENTATION_2, CAMERA_LENS_FACING_2),
+                AttributionSource.myAttributionSource());
 
         mVirtualCameraController.close();
 
@@ -160,11 +165,12 @@
             int lensFacing) {
         mVirtualCameraController.registerCamera(createVirtualCameraConfig(
                 CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1, CAMERA_NAME_1,
-                CAMERA_SENSOR_ORIENTATION_1, lensFacing));
+                CAMERA_SENSOR_ORIENTATION_1, lensFacing), AttributionSource.myAttributionSource());
         assertThrows(IllegalArgumentException.class,
                 () -> mVirtualCameraController.registerCamera(createVirtualCameraConfig(
-                        CAMERA_WIDTH_2, CAMERA_HEIGHT_2, CAMERA_FORMAT_2, CAMERA_MAX_FPS_2,
-                        CAMERA_NAME_2, CAMERA_SENSOR_ORIENTATION_2, lensFacing)));
+                                CAMERA_WIDTH_2, CAMERA_HEIGHT_2, CAMERA_FORMAT_2, CAMERA_MAX_FPS_2,
+                                CAMERA_NAME_2, CAMERA_SENSOR_ORIENTATION_2, lensFacing),
+                        AttributionSource.myAttributionSource()));
     }
 
     @Parameters(method = "getAllLensFacingDirections")
@@ -176,8 +182,9 @@
 
         assertThrows(IllegalArgumentException.class,
                 () -> mVirtualCameraController.registerCamera(createVirtualCameraConfig(
-                        CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1,
-                        CAMERA_NAME_1, CAMERA_SENSOR_ORIENTATION_1, lensFacing)));
+                                CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1, CAMERA_MAX_FPS_1,
+                                CAMERA_NAME_1, CAMERA_SENSOR_ORIENTATION_1, lensFacing),
+                        AttributionSource.myAttributionSource()));
     }
 
     private VirtualCameraConfig createVirtualCameraConfig(
@@ -203,7 +210,7 @@
     }
 
     private static Integer[] getAllLensFacingDirections() {
-        return new Integer[] {
+        return new Integer[]{
                 LENS_FACING_BACK,
                 LENS_FACING_FRONT
         };
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 3492935..a529382 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -2144,13 +2144,14 @@
         assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainEnabled() throws Exception {
         verify(mNetworkManager).setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true);
     }
 
-
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainOnProcStateChange() throws Exception {
@@ -2180,6 +2181,7 @@
         assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainOnAllowlistChange() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java b/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
index da8ec2e..f91f77a 100644
--- a/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pdb/PersistentDataBlockServiceTest.java
@@ -17,12 +17,17 @@
 package com.android.server.pdb;
 
 import static com.android.server.pdb.PersistentDataBlockService.DIGEST_SIZE_BYTES;
+import static com.android.server.pdb.PersistentDataBlockService.FRP_CREDENTIAL_RESERVED_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.FRP_SECRET_MAGIC;
 import static com.android.server.pdb.PersistentDataBlockService.FRP_SECRET_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.HEADER_SIZE;
 import static com.android.server.pdb.PersistentDataBlockService.MAX_DATA_BLOCK_SIZE;
 import static com.android.server.pdb.PersistentDataBlockService.MAX_FRP_CREDENTIAL_HANDLE_SIZE;
 import static com.android.server.pdb.PersistentDataBlockService.MAX_TEST_MODE_DATA_SIZE;
+import static com.android.server.pdb.PersistentDataBlockService.TEST_MODE_RESERVED_SIZE;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -36,6 +41,7 @@
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -63,6 +69,7 @@
 import java.nio.file.StandardOpenOption;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
 
 @RunWith(JUnitParamsRunner.class)
 public class PersistentDataBlockServiceTest {
@@ -397,6 +404,68 @@
 
     @Test
     @Parameters({"false", "true"})
+    public void testPartitionFormat(boolean frpEnabled) throws Exception {
+        setUp(frpEnabled);
+
+        /*
+         * 1. Fill the PDB with a specific value, so we can check regions that weren't touched
+         *    by formatting
+         */
+        FileChannel channel = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.WRITE,
+                StandardOpenOption.TRUNCATE_EXISTING);
+        byte[] bufArray = new byte[(int) mPdbService.getBlockDeviceSize()];
+        Arrays.fill(bufArray, (byte) 0x7f);
+        ByteBuffer buf = ByteBuffer.wrap(bufArray);
+        channel.write(buf);
+        channel.close();
+
+        /*
+         * 2. Format it.
+         */
+        mPdbService.formatPartitionLocked(true);
+
+        /*
+         * 3. Check it.
+         */
+        channel = FileChannel.open(mDataBlockFile.toPath(), StandardOpenOption.READ);
+
+        // 3a. Skip the digest and header
+        channel.position(channel.position() + DIGEST_SIZE_BYTES + HEADER_SIZE);
+
+        // 3b. Check the FRP data segment
+        assertContains("FRP data", readData(channel, mPdbService.getMaximumFrpDataSize()).array(),
+                (byte) 0);
+
+        if (frpEnabled) {
+            // 3c. The FRP secret magic & value
+            assertThat(mPdbService.getFrpSecretMagicOffset()).isEqualTo(channel.position());
+            assertThat(readData(channel, FRP_SECRET_MAGIC.length).array()).isEqualTo(
+                    FRP_SECRET_MAGIC);
+
+            assertThat(mPdbService.getFrpSecretDataOffset()).isEqualTo(channel.position());
+            assertContains("FRP secret", readData(channel, FRP_SECRET_SIZE).array(), (byte) 0);
+        }
+
+        // 3d. The test mode data (unmodified by formatPartitionLocked()).
+        assertThat(mPdbService.getTestHarnessModeDataOffset()).isEqualTo(channel.position());
+        assertContains("Test data", readData(channel, TEST_MODE_RESERVED_SIZE).array(),
+                (byte) 0x7f);
+
+        // 3e. The FRP credential segment
+        assertThat(mPdbService.getFrpCredentialDataOffset()).isEqualTo(channel.position());
+        assertContains("FRP credential", readData(channel, FRP_CREDENTIAL_RESERVED_SIZE).array(),
+                (byte) 0);
+
+        // 3f. OEM unlock byte.
+        assertThat(mPdbService.getOemUnlockDataOffset()).isEqualTo(channel.position());
+        assertThat(new byte[]{1}).isEqualTo(readData(channel, 1).array());
+
+        // 3g. EOF
+        assertThat(channel.position()).isEqualTo(channel.size());
+    }
+
+    @Test
+    @Parameters({"false", "true"})
     public void wipePermissionCheck(boolean frpEnabled) throws Exception {
         setUp(frpEnabled);
         denyOemUnlockPermission();
@@ -987,4 +1056,20 @@
             return buffer;
         }
     }
+
+    @NonNull
+    private static ByteBuffer readData(FileChannel channel, int length) throws IOException {
+        ByteBuffer buf = ByteBuffer.allocate(length);
+        assertThat(channel.read(buf)).isEqualTo(length);
+        buf.flip();
+        assertThat(buf.limit()).isEqualTo(length);
+        return buf;
+    }
+
+    private static void assertContains(String sectionName, byte[] buf, byte expected) {
+        for (int i = 0; i < buf.length; i++) {
+            assertWithMessage(sectionName + " is incorrect at offset " + i)
+                    .that(buf[i]).isEqualTo(expected);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index ae0a758..65662d6 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.webkit;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
@@ -179,4 +180,7 @@
     public boolean isMultiProcessDefaultEnabled() {
         return mMultiProcessDefault;
     }
+
+    @Override
+    public void pinWebviewIfRequired(ApplicationInfo appInfo) {}
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 94d24a9..92dad25 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -595,6 +595,7 @@
                 .thenReturn(INVALID_TASK_ID);
         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
         when(mUm.getProfileIds(eq(mUserId), eq(false))).thenReturn(new int[] { mUserId });
+        when(mAmi.getCurrentUserId()).thenReturn(mUserId);
 
         when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true);
 
diff --git a/services/tests/vibrator/Android.bp b/services/tests/vibrator/Android.bp
index 66dcaff..da21cd3 100644
--- a/services/tests/vibrator/Android.bp
+++ b/services/tests/vibrator/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_haptics_framework",
     // 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"
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index f080341..f54c7e5 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -100,6 +100,8 @@
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
+    private static final int OLD_USER_ID = 123;
+    private static final int NEW_USER_ID = 456;
     private static final int UID = 1;
     private static final int VIRTUAL_DEVICE_ID = 1;
     private static final String SYSUI_PACKAGE_NAME = "sysui";
@@ -211,10 +213,10 @@
         mVibrationSettings.addListener(mListenerMock);
 
         // Testing the broadcast flow manually.
-        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
-                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID);
+        mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
 
-        verify(mListenerMock).onChange();
+        verify(mListenerMock, times(2)).onChange();
     }
 
     @Test
@@ -265,8 +267,7 @@
         // Trigger multiple observers manually.
         mVibrationSettings.mSettingObserver.onChange(false);
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
-                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
         mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
                 new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
 
@@ -834,13 +835,17 @@
         assertEquals(VIBRATION_INTENSITY_HIGH,
                 mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
 
-        // Switching user is not working with FakeSettingsProvider.
-        // Testing the broadcast flow manually.
-        Settings.System.putIntForUser(mContextSpy.getContentResolver(),
-                Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
+        // Test early update of settings based on new user id.
+        putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
+                NEW_USER_ID);
+        mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID);
+        assertEquals(VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
+
+        // Test later update of settings for UserHandle.USER_CURRENT.
+        putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
                 UserHandle.USER_CURRENT);
-        mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
-                new Intent(Intent.ACTION_USER_SWITCHED));
+        mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
         assertEquals(VIBRATION_INTENSITY_LOW,
                 mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
     }
@@ -956,12 +961,16 @@
     }
 
     private void setUserSetting(String settingName, int value) {
-        Settings.System.putIntForUser(
-                mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
+        putUserSetting(settingName, value, UserHandle.USER_CURRENT);
         // FakeSettingsProvider doesn't support testing triggering ContentObserver yet.
         mVibrationSettings.mSettingObserver.onChange(false);
     }
 
+    private void putUserSetting(String settingName, int value, int userHandle) {
+        Settings.System.putIntForUser(
+                mContextSpy.getContentResolver(), settingName, value, userHandle);
+    }
+
     private void setRingerMode(int ringerMode) {
         when(mAudioManagerMock.getRingerModeInternal()).thenReturn(ringerMode);
         // Mock AudioManager broadcast of internal ringer mode change.
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 5d14334..5965fae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -39,6 +39,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 
 import static org.junit.Assert.assertEquals;
@@ -388,6 +389,24 @@
         // The current insets are restored from cache directly.
         assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation,
                 info.logicalWidth, info.logicalHeight).mConfigFrame);
+
+        // If screen is not fully turned on, then the cache should be preserved.
+        displayPolicy.screenTurnedOff();
+        final TransitionController transitionController = mDisplayContent.mTransitionController;
+        spyOn(transitionController);
+        doReturn(true).when(transitionController).isCollecting();
+        doReturn(Integer.MAX_VALUE).when(transitionController).getCollectingTransitionId();
+        // Make CachedDecorInsets.canPreserve return false.
+        displayPolicy.physicalDisplayUpdated();
+        assertFalse(displayPolicy.shouldKeepCurrentDecorInsets());
+        displayPolicy.getDecorInsetsInfo(info.rotation, info.logicalWidth, info.logicalHeight)
+                .mConfigFrame.offset(1, 1);
+        // Even if CachedDecorInsets.canPreserve returns false, the cache won't be cleared.
+        displayPolicy.updateDecorInsetsInfo();
+        // Successful to restore from cache.
+        displayPolicy.updateCachedDecorInsets();
+        assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation,
+                info.logicalWidth, info.logicalHeight).mConfigFrame);
     }
 
     @Test
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 f42cdb8..b96f39d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -22,6 +22,7 @@
 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.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -46,6 +47,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -100,6 +102,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.RemoteException;
@@ -153,6 +156,8 @@
     private static final String CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES =
             "never_constrain_display_apis_all_packages";
 
+    private static final float DELTA_ASPECT_RATIO_TOLERANCE = 0.005f;
+
     @Rule
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
 
@@ -211,90 +216,46 @@
 
     @Test
     public void testHorizontalReachabilityEnabledForTranslucentActivities() {
-        setUpDisplaySizeWithApp(2500, 1000);
-        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
-        final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
-        config.setTranslucentLetterboxingOverrideEnabled(true);
-        config.setLetterboxHorizontalPositionMultiplier(0.5f);
-        config.setIsHorizontalReachabilityEnabled(true);
+        testReachabilityEnabledForTranslucentActivity(/* dw */ 2500,  /* dh */1000,
+                SCREEN_ORIENTATION_PORTRAIT, /* minAspectRatio */ 0f,
+                /* horizontalReachability */ true);
+    }
 
-        // Opaque activity
-        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
-        addWindowToActivity(mActivity);
-        mActivity.mRootWindowContainer.performSurfacePlacement();
-
-        // Translucent Activity
-        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
-                .setActivityTheme(android.R.style.Theme_Translucent)
-                .setLaunchedFromUid(mActivity.getUid())
-                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
-                .build();
-        mTask.addChild(translucentActivity);
-
-        spyOn(translucentActivity.mLetterboxUiController);
-        doReturn(true).when(translucentActivity.mLetterboxUiController)
-                .shouldShowLetterboxUi(any());
-
-        addWindowToActivity(translucentActivity);
-        translucentActivity.mRootWindowContainer.performSurfacePlacement();
-
-        final Function<ActivityRecord, Rect> innerBoundsOf =
-                (ActivityRecord a) -> {
-                    final Rect bounds = new Rect();
-                    a.mLetterboxUiController.getLetterboxInnerBounds(bounds);
-                    return bounds;
-                };
-        final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity),
-                innerBoundsOf.apply(translucentActivity));
-        final Runnable checkIsLeft = () -> assertThat(
-                innerBoundsOf.apply(translucentActivity).left).isEqualTo(0);
-        final Runnable checkIsRight = () -> assertThat(
-                innerBoundsOf.apply(translucentActivity).right).isEqualTo(2500);
-        final Runnable checkIsCentered = () -> assertThat(
-                innerBoundsOf.apply(translucentActivity).left > 0
-                        && innerBoundsOf.apply(translucentActivity).right < 2500).isTrue();
-
-        final Consumer<Integer> doubleClick =
-                (Integer x) -> {
-                    mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x);
-                    mActivity.mRootWindowContainer.performSurfacePlacement();
-                };
-
-        // Initial state
-        checkIsCentered.run();
-
-        // Double-click left
-        doubleClick.accept(/* x */ 10);
-        checkLetterboxPositions.run();
-        checkIsLeft.run();
-
-        // Double-click right
-        doubleClick.accept(/* x */ 1990);
-        checkLetterboxPositions.run();
-        checkIsCentered.run();
-
-        // Double-click right
-        doubleClick.accept(/* x */ 1990);
-        checkLetterboxPositions.run();
-        checkIsRight.run();
-
-        // Double-click left
-        doubleClick.accept(/* x */ 10);
-        checkLetterboxPositions.run();
-        checkIsCentered.run();
+    @Test
+    public void testHorizontalReachabilityEnabled_TranslucentPortraitActivities_portraitDisplay() {
+        testReachabilityEnabledForTranslucentActivity(/* dw */ 1400,  /* dh */1600,
+                SCREEN_ORIENTATION_PORTRAIT, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                /* horizontalReachability */ true);
     }
 
     @Test
     public void testVerticalReachabilityEnabledForTranslucentActivities() {
-        setUpDisplaySizeWithApp(1000, 2500);
+        testReachabilityEnabledForTranslucentActivity(/* dw */ 1000,  /* dh */2500,
+                SCREEN_ORIENTATION_LANDSCAPE, /* minAspectRatio */ 0f,
+                /* horizontalReachability */ false);
+    }
+
+    @Test
+    public void testVerticalReachabilityEnabled_TranslucentLandscapeActivities_landscapeDisplay() {
+        testReachabilityEnabledForTranslucentActivity(/* dw */ 1600,  /* dh */1400,
+                SCREEN_ORIENTATION_LANDSCAPE, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                /* horizontalReachability */ false);
+    }
+
+    private void testReachabilityEnabledForTranslucentActivity(int displayWidth, int displayHeight,
+            @ScreenOrientation int screenOrientation, float minAspectRatio,
+            boolean horizontalReachability) {
+        setUpDisplaySizeWithApp(displayWidth, displayHeight);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
         config.setTranslucentLetterboxingOverrideEnabled(true);
         config.setLetterboxVerticalPositionMultiplier(0.5f);
         config.setIsVerticalReachabilityEnabled(true);
+        config.setLetterboxHorizontalPositionMultiplier(0.5f);
+        config.setIsHorizontalReachabilityEnabled(true);
 
         // Opaque activity
-        prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+        prepareMinAspectRatio(mActivity, minAspectRatio, screenOrientation);
         addWindowToActivity(mActivity);
         mActivity.mRootWindowContainer.performSurfacePlacement();
 
@@ -302,7 +263,7 @@
         final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                 .setActivityTheme(android.R.style.Theme_Translucent)
                 .setLaunchedFromUid(mActivity.getUid())
-                .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
+                .setScreenOrientation(screenOrientation)
                 .build();
         mTask.addChild(translucentActivity);
 
@@ -324,39 +285,78 @@
         final Runnable checkIsTop = () -> assertThat(
                 innerBoundsOf.apply(translucentActivity).top).isEqualTo(0);
         final Runnable checkIsBottom = () -> assertThat(
-                innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(2500);
-        final Runnable checkIsCentered = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(displayHeight);
+        final Runnable checkIsLeft = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).left).isEqualTo(0);
+        final Runnable checkIsRight = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).right).isEqualTo(displayWidth);
+        final Runnable checkIsHorizontallyCentered = () -> assertThat(
+                innerBoundsOf.apply(translucentActivity).left > 0
+                        && innerBoundsOf.apply(translucentActivity).right < displayWidth).isTrue();
+        final Runnable checkIsVerticallyCentered = () -> assertThat(
                 innerBoundsOf.apply(translucentActivity).top > 0
-                        && innerBoundsOf.apply(translucentActivity).bottom < 2500).isTrue();
+                        && innerBoundsOf.apply(translucentActivity).bottom < displayHeight)
+                .isTrue();
 
-        final Consumer<Integer> doubleClick =
-                (Integer y) -> {
-                    mActivity.mLetterboxUiController.handleVerticalDoubleTap(y);
-                    mActivity.mRootWindowContainer.performSurfacePlacement();
-                };
+        if (horizontalReachability) {
+            final Consumer<Integer> doubleClick =
+                    (Integer x) -> {
+                        mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x);
+                        mActivity.mRootWindowContainer.performSurfacePlacement();
+                    };
 
-        // Initial state
-        checkIsCentered.run();
+            // Initial state
+            checkIsHorizontallyCentered.run();
 
-        // Double-click top
-        doubleClick.accept(/* y */ 10);
-        checkLetterboxPositions.run();
-        checkIsTop.run();
+            // Double-click left
+            doubleClick.accept(/* x */ 10);
+            checkLetterboxPositions.run();
+            checkIsLeft.run();
 
-        // Double-click bottom
-        doubleClick.accept(/* y */ 1990);
-        checkLetterboxPositions.run();
-        checkIsCentered.run();
+            // Double-click right
+            doubleClick.accept(/* x */ displayWidth - 100);
+            checkLetterboxPositions.run();
+            checkIsHorizontallyCentered.run();
 
-        // Double-click bottom
-        doubleClick.accept(/* y */ 1990);
-        checkLetterboxPositions.run();
-        checkIsBottom.run();
+            // Double-click right
+            doubleClick.accept(/* x */ displayWidth - 100);
+            checkLetterboxPositions.run();
+            checkIsRight.run();
 
-        // Double-click top
-        doubleClick.accept(/* y */ 10);
-        checkLetterboxPositions.run();
-        checkIsCentered.run();
+            // Double-click left
+            doubleClick.accept(/* x */ 10);
+            checkLetterboxPositions.run();
+            checkIsHorizontallyCentered.run();
+        } else {
+            final Consumer<Integer> doubleClick =
+                    (Integer y) -> {
+                        mActivity.mLetterboxUiController.handleVerticalDoubleTap(y);
+                        mActivity.mRootWindowContainer.performSurfacePlacement();
+                    };
+
+            // Initial state
+            checkIsVerticallyCentered.run();
+
+            // Double-click top
+            doubleClick.accept(/* y */ 10);
+            checkLetterboxPositions.run();
+            checkIsTop.run();
+
+            // Double-click bottom
+            doubleClick.accept(/* y */ displayHeight - 100);
+            checkLetterboxPositions.run();
+            checkIsVerticallyCentered.run();
+
+            // Double-click bottom
+            doubleClick.accept(/* y */ displayHeight - 100);
+            checkLetterboxPositions.run();
+            checkIsBottom.run();
+
+            // Double-click top
+            doubleClick.accept(/* y */ 10);
+            checkLetterboxPositions.run();
+            checkIsVerticallyCentered.run();
+        }
     }
 
     @Test
@@ -2143,7 +2143,7 @@
         final Rect afterBounds = mActivity.getBounds();
         final float actualAspectRatio = 1f * afterBounds.height() / afterBounds.width();
         assertEquals(LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW,
-                actualAspectRatio, 0.001f);
+                actualAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
         assertTrue(mActivity.areBoundsLetterboxed());
     }
 
@@ -2179,7 +2179,7 @@
         // default letterbox aspect ratio for multi-window.
         final Rect afterBounds = mActivity.getBounds();
         final float actualAspectRatio = 1f * afterBounds.height() / afterBounds.width();
-        assertEquals(minAspectRatio, actualAspectRatio, 0.001f);
+        assertEquals(minAspectRatio, actualAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
         assertTrue(mActivity.areBoundsLetterboxed());
     }
 
@@ -2487,7 +2487,7 @@
         final float afterAspectRatio =
                 (float) Math.max(width, height) / (float) Math.min(width, height);
 
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2512,7 +2512,7 @@
         float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
         final Rect afterBounds = activity.getBounds();
         final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2537,7 +2537,7 @@
         float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
         final Rect afterBounds = activity.getBounds();
         final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2563,7 +2563,7 @@
         float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
         final Rect afterBounds = activity.getBounds();
         final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2589,7 +2589,7 @@
         float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
         final Rect afterBounds = activity.getBounds();
         final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2629,7 +2629,7 @@
         float expectedAspectRatio = 1f * screenHeight / getExpectedSplitSize(screenWidth);
         final Rect afterBounds = activity.getBounds();
         final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
         assertFalse(activity.areBoundsLetterboxed());
     }
 
@@ -2670,7 +2670,7 @@
         float expectedAspectRatio = 1f * screenWidth / getExpectedSplitSize(screenHeight);
         final Rect afterBounds = activity.getBounds();
         final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
-        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
+        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
         assertFalse(activity.areBoundsLetterboxed());
     }
 
@@ -2847,9 +2847,8 @@
         assertFitted();
         // Check that the display aspect ratio is used by the app.
         final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
-        final float delta = 0.01f;
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(mActivity.getBounds()), delta);
+                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2883,9 +2882,8 @@
         assertFitted();
         // Check that the display aspect ratio is used by the app.
         final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
-        final float delta = 0.01f;
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(mActivity.getBounds()), delta);
+                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2910,9 +2908,8 @@
         assertFitted();
         // Check that the display aspect ratio is used by the app.
         final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
-        final float delta = 0.01f;
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(mActivity.getBounds()), delta);
+                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -2937,9 +2934,8 @@
         assertFitted();
         // Check that the display aspect ratio is used by the app.
         final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
-        final float delta = 0.01f;
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(mActivity.getBounds()), delta);
+                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -3609,6 +3605,32 @@
     }
 
     @Test
+    public void testIsHorizontalReachabilityEnabled_portraitDisplayAndApp_true() {
+        // Portrait display
+        setUpDisplaySizeWithApp(1400, 1600);
+        mActivity.mWmService.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true);
+
+        // 16:9f unresizable portrait app
+        prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                SCREEN_ORIENTATION_PORTRAIT);
+
+        assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled());
+    }
+
+    @Test
+    public void testIsVerticalReachabilityEnabled_landscapeDisplayAndApp_true() {
+        // Landscape display
+        setUpDisplaySizeWithApp(1600, 1500);
+        mActivity.mWmService.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
+
+        // 16:9f unresizable landscape app
+        prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                SCREEN_ORIENTATION_LANDSCAPE);
+
+        assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled());
+    }
+
+    @Test
     public void testIsHorizontalReachabilityEnabled_doesNotMatchParentHeight_false() {
         setUpDisplaySizeWithApp(2800, 1000);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -4053,6 +4075,32 @@
     }
 
     @Test
+    public void testPortraitCloseToSquareDisplayWithTaskbar_notLetterboxed() {
+        // Set up portrait close to square display
+        setUpDisplaySizeWithApp(2200, 2280);
+        final DisplayContent display = mActivity.mDisplayContent;
+        // Simulate taskbar, final app bounds are (0, 0, 2200, 2130) - landscape
+        final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
+                "navbar");
+        final Binder owner = new Binder();
+        navbar.mAttrs.providedInsets = new InsetsFrameProvider[] {
+                new InsetsFrameProvider(owner, 0, WindowInsets.Type.navigationBars())
+                        .setInsetsSize(Insets.of(0, 0, 0, 150))
+        };
+        display.getDisplayPolicy().addWindowLw(navbar, navbar.mAttrs);
+        assertTrue(navbar.providesDisplayDecorInsets()
+                && display.getDisplayPolicy().updateDecorInsetsInfo());
+        display.sendNewConfiguration();
+
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+        // Activity is fullscreen even though orientation is not respected with insets, because
+        // the display still matches or is less than the activity aspect ratio
+        assertEquals(display.getBounds(), mActivity.getBounds());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+    }
+
+    @Test
     public void testApplyAspectRatio_activityAlignWithParentAppVertical() {
         // The display's app bounds will be (0, 100, 1000, 2350)
         final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500)
@@ -4275,7 +4323,7 @@
                 .getFixedOrientationLetterboxAspectRatio(parentConfig);
         float expected = mActivity.mLetterboxUiController.getSplitScreenAspectRatio();
 
-        assertEquals(expected, actual, 0.01);
+        assertEquals(expected, actual, DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -4671,13 +4719,12 @@
                 .windowConfiguration.getAppBounds());
 
         // Check that aspect ratio of app bounds is equal to the min aspect ratio.
-        final float delta = 0.01f;
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(fixedOrientationAppBounds), delta);
+                .computeAspectRatio(fixedOrientationAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(minAspectRatioAppBounds), delta);
+                .computeAspectRatio(minAspectRatioAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
         assertEquals(targetMinAspectRatio, ActivityRecord
-                .computeAspectRatio(sizeCompatAppBounds), delta);
+                .computeAspectRatio(sizeCompatAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
     }
 
     @Test
@@ -4859,6 +4906,12 @@
                 .build();
     }
 
+    static void prepareMinAspectRatio(ActivityRecord activity, float minAspect,
+            int screenOrientation) {
+        prepareLimitedBounds(activity, -1 /* maxAspect */, minAspect, screenOrientation,
+                true /* isUnresizable */);
+    }
+
     static void prepareUnresizable(ActivityRecord activity, int screenOrientation) {
         prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation);
     }
@@ -4873,12 +4926,18 @@
         prepareLimitedBounds(activity, -1 /* maxAspect */, screenOrientation, isUnresizable);
     }
 
-    /**
-     * Setups {@link #mActivity} with restriction on its bounds, such as maxAspect, fixed
-     * orientation, and/or whether it is resizable.
-     */
     static void prepareLimitedBounds(ActivityRecord activity, float maxAspect,
             int screenOrientation, boolean isUnresizable) {
+        prepareLimitedBounds(activity, maxAspect, -1 /* minAspect */, screenOrientation,
+                isUnresizable);
+    }
+
+    /**
+     * Setups {@link #mActivity} with restriction on its bounds, such as maxAspect, minAspect,
+     * fixed orientation, and/or whether it is resizable.
+     */
+    static void prepareLimitedBounds(ActivityRecord activity, float maxAspect, float minAspect,
+            int screenOrientation, boolean isUnresizable) {
         activity.info.resizeMode = isUnresizable
                 ? RESIZE_MODE_UNRESIZEABLE
                 : RESIZE_MODE_RESIZEABLE;
@@ -4892,6 +4951,9 @@
         if (maxAspect >= 0) {
             activity.info.setMaxAspectRatio(maxAspect);
         }
+        if (minAspect >= 0) {
+            activity.info.setMinAspectRatio(minAspect);
+        }
         if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
             activity.info.screenOrientation = screenOrientation;
             activity.setRequestedOrientation(screenOrientation);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 295b124..a8f6fe8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -346,7 +346,7 @@
         doReturn(true).when(amInternal).hasStartedUserState(anyInt());
         doReturn(false).when(amInternal).shouldConfirmCredentials(anyInt());
         doReturn(false).when(amInternal).isActivityStartsLoggingEnabled();
-        doReturn(true).when(amInternal).getThemeOverlayReadiness();
+        doReturn(true).when(amInternal).isThemeOverlayReady(anyInt());
         LocalServices.addService(ActivityManagerInternal.class, amInternal);
 
         final ActivityManagerService amService =
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
index 6a15b05..f1d84cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
@@ -40,8 +40,10 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.server.wm.utils.CommonUtils;
 import com.android.window.flags.Flags;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -77,6 +79,11 @@
         });
     }
 
+    @After
+    public void tearDown() {
+        CommonUtils.waitUntilActivityRemoved(mActivity);
+    }
+
     @RequiresFlagsDisabled(Flags.FLAG_SURFACE_TRUSTED_OVERLAY)
     @Test
     public void setTrustedOverlayInputWindow() throws InterruptedException {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 4da519c..c972e51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -240,6 +240,22 @@
     }
 
     @Test
+    public void testTrackOverlayWindow() {
+        final WindowProcessController wpc = mSystemServicesTestRule.addProcess(
+                "pkgName", "processName", 1000 /* pid */, Process.SYSTEM_UID);
+        final Session session = createTestSession(mAtm, wpc.getPid(), wpc.mUid);
+        spyOn(session);
+        assertTrue(session.mCanAddInternalSystemWindow);
+        final WindowSurfaceController winSurface = mock(WindowSurfaceController.class);
+        session.onWindowSurfaceVisibilityChanged(winSurface, true /* visible */,
+                LayoutParams.TYPE_PHONE);
+        verify(session).setHasOverlayUi(true);
+        session.onWindowSurfaceVisibilityChanged(winSurface, false /* visible */,
+                LayoutParams.TYPE_PHONE);
+        verify(session).setHasOverlayUi(false);
+    }
+
+    @Test
     public void testRelayoutExitingWindow() {
         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin");
         final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index 368a96b..0a1f3c7 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -192,6 +192,7 @@
     final Object mLock;
     final int mVoiceInteractionServiceUid;
     final Context mContext;
+    final int mUserId;
 
     @Nullable AttentionManagerInternal mAttentionManagerInternal = null;
 
@@ -224,12 +225,13 @@
             @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid,
             Identity voiceInteractorIdentity,
             @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging,
-            @NonNull DetectorRemoteExceptionListener listener) {
+            @NonNull DetectorRemoteExceptionListener listener, int userId) {
         mRemoteExceptionListener = listener;
         mRemoteDetectionService = remoteDetectionService;
         mLock = lock;
         mContext = context;
         mToken = token;
+        mUserId = userId;
         mCallback = callback;
         mVoiceInteractionServiceUid = voiceInteractionServiceUid;
         mVoiceInteractorIdentity = voiceInteractorIdentity;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
index 9a4fbdc..8d08c6b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
@@ -87,10 +87,10 @@
             @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid,
             Identity voiceInteractorIdentity,
             @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging,
-            @NonNull DetectorRemoteExceptionListener listener) {
+            @NonNull DetectorRemoteExceptionListener listener, int userId) {
         super(remoteHotwordDetectionService, lock, context, token, callback,
                 voiceInteractionServiceUid, voiceInteractorIdentity, scheduledExecutorService,
-                logging, listener);
+                logging, listener, userId);
     }
 
     @SuppressWarnings("GuardedBy")
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index f1f5458..cfcc04b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -72,6 +72,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVisualQueryDetectionAttentionListener;
+import com.android.internal.app.IVoiceInteractionAccessibilitySettingsListener;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.infra.ServiceConnector;
 import com.android.server.LocalServices;
@@ -147,8 +148,9 @@
     final int mVoiceInteractionServiceUid;
     final ComponentName mHotwordDetectionComponentName;
     final ComponentName mVisualQueryDetectionComponentName;
-    final int mUser;
+    final int mUserId;
     final Context mContext;
+    final AccessibilitySettingsListener mAccessibilitySettingsListener;
     volatile HotwordDetectionServiceIdentity mIdentity;
     //TODO: Consider rename this to SandboxedDetectionIdentity
     private Instant mLastRestartInstant;
@@ -204,6 +206,27 @@
                 }
             };
 
+    /** Listen to changes of {@link Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED}.
+     *
+     * This is registered to the {@link VoiceInteractionManagerServiceImpl} where all settings
+     * listeners are centralized and notified.
+     */
+    private final class AccessibilitySettingsListener extends
+            IVoiceInteractionAccessibilitySettingsListener.Stub {
+        @Override
+        public void onAccessibilityDetectionChanged(boolean enable) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Update settings change: " + enable);
+                }
+                VisualQueryDetectorSession session = getVisualQueryDetectorSessionLocked();
+                if (session != null) {
+                    session.updateAccessibilityEgressStateLocked(enable);
+                }
+            }
+        }
+    }
+
 
     HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
             Identity voiceInteractorIdentity, ComponentName hotwordDetectionServiceName,
@@ -216,11 +239,12 @@
         mVoiceInteractorIdentity = voiceInteractorIdentity;
         mHotwordDetectionComponentName = hotwordDetectionServiceName;
         mVisualQueryDetectionComponentName = visualQueryDetectionServiceName;
-        mUser = userId;
+        mUserId = userId;
         mDetectorType = detectorType;
         mRemoteExceptionListener = listener;
         mReStartPeriodSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION,
                 KEY_RESTART_PERIOD_IN_SECONDS, 0);
+        mAccessibilitySettingsListener = new AccessibilitySettingsListener();
 
         final Intent hotwordDetectionServiceIntent =
                 new Intent(HotwordDetectionService.SERVICE_INTERFACE);
@@ -792,7 +816,7 @@
 
         ServiceConnection createLocked() {
             ServiceConnection connection =
-                    new ServiceConnection(mContext, mIntent, mBindingFlags, mUser,
+                    new ServiceConnection(mContext, mIntent, mBindingFlags, mUserId,
                             ISandboxedDetectionService.Stub::asInterface,
                             mRestartCount % MAX_ISOLATED_PROCESS_NUMBER, mDetectionServiceType);
             connection.connect();
@@ -998,7 +1022,7 @@
             session = new DspTrustedHotwordDetectorSession(mRemoteHotwordDetectionService,
                     mLock, mContext, token, callback, mVoiceInteractionServiceUid,
                     mVoiceInteractorIdentity, mScheduledExecutorService, mDebugHotwordLogging,
-                    mRemoteExceptionListener);
+                    mRemoteExceptionListener, mUserId);
         } else if (detectorType == HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
             if (mRemoteVisualQueryDetectionService == null) {
                 mRemoteVisualQueryDetectionService =
@@ -1007,7 +1031,8 @@
             session = new VisualQueryDetectorSession(
                     mRemoteVisualQueryDetectionService, mLock, mContext, token, callback,
                     mVoiceInteractionServiceUid, mVoiceInteractorIdentity,
-                    mScheduledExecutorService, mDebugHotwordLogging, mRemoteExceptionListener);
+                    mScheduledExecutorService, mDebugHotwordLogging, mRemoteExceptionListener,
+                    mUserId);
         } else {
             if (mRemoteHotwordDetectionService == null) {
                 mRemoteHotwordDetectionService =
@@ -1016,7 +1041,8 @@
             session = new SoftwareTrustedHotwordDetectorSession(
                     mRemoteHotwordDetectionService, mLock, mContext, token, callback,
                     mVoiceInteractionServiceUid, mVoiceInteractorIdentity,
-                    mScheduledExecutorService, mDebugHotwordLogging, mRemoteExceptionListener);
+                    mScheduledExecutorService, mDebugHotwordLogging,
+                    mRemoteExceptionListener, mUserId);
         }
         mHotwordRecognitionCallback = callback;
         mDetectorSessions.put(detectorType, session);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
index f06c997..120c161 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
@@ -74,10 +74,10 @@
             @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid,
             Identity voiceInteractorIdentity,
             @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging,
-            @NonNull DetectorRemoteExceptionListener listener) {
+            @NonNull DetectorRemoteExceptionListener listener, int userId) {
         super(remoteHotwordDetectionService, lock, context, token, callback,
                 voiceInteractionServiceUid, voiceInteractorIdentity, scheduledExecutorService,
-                logging, listener);
+                logging, listener, userId);
     }
 
     @SuppressWarnings("GuardedBy")
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
index e4ac993..aef8e6f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
@@ -29,6 +29,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SharedMemory;
+import android.provider.Settings;
 import android.service.voice.IDetectorSessionVisualQueryDetectionCallback;
 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
 import android.service.voice.ISandboxedDetectionService;
@@ -60,6 +61,7 @@
     private IVisualQueryDetectionAttentionListener mAttentionListener;
     private boolean mEgressingData;
     private boolean mQueryStreaming;
+    private boolean mEnableAccessibilityDataEgress;
 
     //TODO(b/261783819): Determines actual functionalities, e.g., startRecognition etc.
     VisualQueryDetectorSession(
@@ -68,13 +70,17 @@
             @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid,
             Identity voiceInteractorIdentity,
             @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging,
-            @NonNull DetectorRemoteExceptionListener listener) {
+            @NonNull DetectorRemoteExceptionListener listener, int userId) {
         super(remoteService, lock, context, token, callback,
                 voiceInteractionServiceUid, voiceInteractorIdentity, scheduledExecutorService,
-                logging, listener);
+                logging, listener, userId);
         mEgressingData = false;
         mQueryStreaming = false;
         mAttentionListener = null;
+        mEnableAccessibilityDataEgress = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED, 0,
+                mUserId) == 1;
         // TODO: handle notify RemoteException to client
     }
 
@@ -186,6 +192,16 @@
                                         "Cannot stream results without attention signals."));
                         return;
                     }
+                    if (!checkDetectedResultDataLocked(partialResult)) {
+                        Slog.v(TAG, "Accessibility data can be egressed only when the "
+                                        + "isAccessibilityDetectionEnabled() is true.");
+                        callback.onVisualQueryDetectionServiceFailure(
+                                new VisualQueryDetectionServiceFailure(
+                                        ERROR_CODE_ILLEGAL_STREAMING_STATE,
+                                        "Cannot stream accessibility data without "
+                                                + "enabling the setting."));
+                        return;
+                    }
                     mQueryStreaming = true;
                     callback.onResultDetected(partialResult);
                     Slog.i(TAG, "Egressed from visual query detection process.");
@@ -227,6 +243,12 @@
                     mQueryStreaming = false;
                 }
             }
+
+            @SuppressWarnings("GuardedBy")
+            private boolean checkDetectedResultDataLocked(VisualQueryDetectedResult result) {
+                return result.getAccessibilityDetectionData() == null
+                        || mEnableAccessibilityDataEgress;
+            }
         };
         return mRemoteDetectionService.run(
                 service -> service.detectWithVisualSignals(internalCallback));
@@ -251,6 +273,12 @@
                 + " should not be called from VisualQueryDetectorSession.");
     }
 
+    void updateAccessibilityEgressStateLocked(boolean enable) {
+        if (DEBUG) {
+            Slog.d(TAG, "updateAccessibilityEgressStateLocked");
+        }
+        mEnableAccessibilityDataEgress = enable;
+    }
 
     @SuppressWarnings("GuardedBy")
     public void dumpLocked(String prefix, PrintWriter pw) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ecb0f96..889f842 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -91,6 +91,7 @@
 import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 import com.android.internal.app.IVisualQueryRecognitionStatusListener;
 import com.android.internal.app.IVoiceActionCheckCallback;
+import com.android.internal.app.IVoiceInteractionAccessibilitySettingsListener;
 import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
@@ -2179,6 +2180,44 @@
             }
         }
 
+        public boolean getAccessibilityDetectionEnabled() {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "registerAccessibilityDetectionSettingsListener called without"
+                            + " running voice interaction service");
+                    return false;
+                }
+                return mImpl.getAccessibilityDetectionEnabled();
+            }
+        }
+
+        @Override
+        public void registerAccessibilityDetectionSettingsListener(
+                IVoiceInteractionAccessibilitySettingsListener listener) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "registerAccessibilityDetectionSettingsListener called without"
+                            + " running voice interaction service");
+                    return;
+                }
+                mImpl.registerAccessibilityDetectionSettingsListenerLocked(listener);
+            }
+        }
+
+        @Override
+        public void unregisterAccessibilityDetectionSettingsListener(
+                IVoiceInteractionAccessibilitySettingsListener listener) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "unregisterAccessibilityDetectionSettingsListener called "
+                            + "without running voice interaction service");
+                    return;
+                }
+                mImpl.unregisterAccessibilityDetectionSettingsListenerLocked(listener);
+            }
+        }
+
+
         @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 84b36d5..e34e819 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -36,6 +36,7 @@
 import android.app.IActivityTaskManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -45,10 +46,12 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.media.AudioFormat;
 import android.media.permission.Identity;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -60,6 +63,7 @@
 import android.os.SharedMemory;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.voice.HotwordDetector;
 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
 import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
@@ -77,6 +81,7 @@
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 import com.android.internal.app.IVoiceActionCheckCallback;
+import com.android.internal.app.IVoiceInteractionAccessibilitySettingsListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -199,6 +204,10 @@
         }
     };
 
+    final ArrayList<
+            IVoiceInteractionAccessibilitySettingsListener> mAccessibilitySettingsListeners =
+            new ArrayList<IVoiceInteractionAccessibilitySettingsListener>();
+
     VoiceInteractionManagerServiceImpl(Context context, Handler handler,
             VoiceInteractionManagerService.VoiceInteractionManagerServiceStub stub,
             int userHandle, ComponentName service) {
@@ -250,6 +259,7 @@
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mContext.registerReceiver(mBroadcastReceiver, filter, null, handler,
                 Context.RECEIVER_EXPORTED);
+        new AccessibilitySettingsContentObserver().register(mContext.getContentResolver());
     }
 
     public void grantImplicitAccessLocked(int grantRecipientUid, @Nullable Intent intent) {
@@ -745,6 +755,8 @@
                                     + "exception occurred.");
                         }
                     });
+            registerAccessibilityDetectionSettingsListenerLocked(
+                    mHotwordDetectionConnection.mAccessibilitySettingsListener);
         } else if (detectorType != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
             // TODO: Logger events should be handled in session instead. Temporary adding the
             //  checking to prevent confusion so VisualQueryDetection events won't be logged if the
@@ -782,6 +794,8 @@
             return;
         }
         mHotwordDetectionConnection.cancelLocked();
+        unregisterAccessibilityDetectionSettingsListenerLocked(
+                mHotwordDetectionConnection.mAccessibilitySettingsListener);
         mHotwordDetectionConnection = null;
     }
 
@@ -974,6 +988,8 @@
             return;
         }
         mHotwordDetectionConnection.cancelLocked();
+        unregisterAccessibilityDetectionSettingsListenerLocked(
+                mHotwordDetectionConnection.mAccessibilitySettingsListener);
         mHotwordDetectionConnection = null;
     }
 
@@ -1015,6 +1031,29 @@
         }
     }
 
+    boolean getAccessibilityDetectionEnabled() {
+        return Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED, 0,
+                mUser) == 1;
+    }
+
+    void registerAccessibilityDetectionSettingsListenerLocked(
+            IVoiceInteractionAccessibilitySettingsListener listener) {
+        if (DEBUG) {
+            Slog.d(TAG, "registerAccessibilityDetectionSettingsListener");
+        }
+        mAccessibilitySettingsListeners.add(listener);
+    }
+
+    void unregisterAccessibilityDetectionSettingsListenerLocked(
+            IVoiceInteractionAccessibilitySettingsListener listener) {
+        if (DEBUG) {
+            Slog.d(TAG, "unregisterAccessibilityDetectionSettingsListener");
+        }
+        mAccessibilitySettingsListeners.remove(listener);
+    }
+
     void startLocked() {
         Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
         intent.setComponent(mComponent);
@@ -1055,6 +1094,8 @@
         }
         if (mHotwordDetectionConnection != null) {
             mHotwordDetectionConnection.cancelLocked();
+            unregisterAccessibilityDetectionSettingsListenerLocked(
+                    mHotwordDetectionConnection.mAccessibilitySettingsListener);
             mHotwordDetectionConnection = null;
         }
         if (mBound) {
@@ -1101,4 +1142,41 @@
     interface DetectorRemoteExceptionListener {
         void onDetectorRemoteException(@NonNull IBinder token, int detectorType);
     }
+
+    private final class AccessibilitySettingsContentObserver extends ContentObserver {
+        private Uri mAccessibilitySettingsEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED);
+
+        AccessibilitySettingsContentObserver() {
+            super(null);
+        }
+
+        public void register(ContentResolver contentResolver) {
+            contentResolver.registerContentObserver(
+                    mAccessibilitySettingsEnabledUri, false, this, UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            Slog.i(TAG, "OnChange called with uri:" + uri);
+            if (mAccessibilitySettingsEnabledUri.equals(uri)) {
+                    boolean enable = Settings.Secure.getIntForUser(
+                            mContext.getContentResolver(),
+                            Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED, 0,
+                            mUser) == 1;
+                    Slog.i(TAG, "Notifying listeners with Accessibility setting set to "
+                            + enable);
+                    mAccessibilitySettingsListeners.forEach(
+                            listener -> {
+                                try {
+                                    listener.onAccessibilityDetectionChanged(enable);
+                                } catch (RemoteException e) {
+                                    e.rethrowFromSystemServer();
+                                }
+                            }
+                    );
+
+            }
+        }
+    }
 }
diff --git a/telecomm/java/Android.bp b/telecomm/java/Android.bp
index 3bd5953..9e9dd7d 100644
--- a/telecomm/java/Android.bp
+++ b/telecomm/java/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_fwk_telephony",
     // 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"
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index c7cc1bd..49e9232 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -199,6 +199,16 @@
     }
 
     /**
+     * @return Bit mask of all routes supported by this call, won't be changed by streaming state.
+     *
+     * @hide
+     */
+    @CallAudioRoute
+    public int getRawSupportedRouteMask() {
+        return supportedRouteMask;
+    }
+
+    /**
      * @return The {@link BluetoothDevice} through which audio is being routed.
      *         Will not be {@code null} if {@link #getRoute()} returns {@link #ROUTE_BLUETOOTH}.
      */
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 15a978d..08c76af 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1434,6 +1434,31 @@
     }
 
     /**
+     * This API will return all {@link PhoneAccount}s registered via
+     * {@link TelecomManager#registerPhoneAccount(PhoneAccount)}. If a {@link PhoneAccount} appears
+     * to be missing from the list, Telecom has either unregistered the {@link PhoneAccount}
+     * or the caller registered the {@link PhoneAccount} under a different user and does not
+     * have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+     *
+     * @return all the {@link PhoneAccount}s registered by the caller.
+     */
+    @SuppressLint("RequiresPermission")
+    @FlaggedApi(Flags.FLAG_GET_REGISTERED_PHONE_ACCOUNTS)
+    public @NonNull List<PhoneAccount> getRegisteredPhoneAccounts() {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                return service.getRegisteredPhoneAccounts(
+                        mContext.getOpPackageName(),
+                        mContext.getAttributionTag()).getList();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        throw new IllegalStateException("Telecom is not available");
+    }
+
+    /**
      * Returns a list of {@link PhoneAccountHandle}s including those which have not been enabled
      * by the user.
      *
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 7dba799e..302a472 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -93,6 +93,12 @@
     PhoneAccount getPhoneAccount(in PhoneAccountHandle account, String callingPackage);
 
     /**
+     * @see TelecomManager#getPhoneAccount
+     */
+    ParceledListSlice<PhoneAccount> getRegisteredPhoneAccounts(String callingPackage,
+            String callingFeatureId);
+
+    /**
      * @see TelecomManager#getAllPhoneAccountsCount
      */
     int getAllPhoneAccountsCount();
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index aed8fb8..a63db88 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -32,6 +32,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Telephony;
+import android.provider.Telephony.Carriers.EditStatus;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.TelephonyManager;
@@ -226,6 +228,23 @@
     }
 
     /**
+     * Convert APN edited status to string.
+     *
+     * @param apnEditStatus APN edited status.
+     * @return APN edited status in string format.
+     */
+    public static @NonNull String apnEditedStatusToString(@EditStatus int apnEditStatus) {
+        return switch (apnEditStatus) {
+            case Telephony.Carriers.UNEDITED -> "UNEDITED";
+            case Telephony.Carriers.USER_EDITED -> "USER_EDITED";
+            case Telephony.Carriers.USER_DELETED -> "USER_DELETED";
+            case Telephony.Carriers.CARRIER_EDITED -> "CARRIER_EDITED";
+            case Telephony.Carriers.CARRIER_DELETED -> "CARRIER_DELETED";
+            default -> "UNKNOWN(" + apnEditStatus + ")";
+        };
+    }
+
+    /**
      * Utility method to get user handle associated with this subscription.
      *
      * This method should be used internally as it returns null instead of throwing
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d99abe8..5d99acd 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4803,12 +4803,51 @@
          */
         public static final String KEY_FCM_SENDER_ID_STRING = KEY_PREFIX + "fcm_sender_id_string";
 
+        /**
+         * Indicates the supported protocol version in the parameter entitlement_version.
+         * The default value is 2. The possible value is 2 and 8.
+         *
+         * Reference: GSMA TS.43-v8 section 2.5 Protocol version control and
+         * Table 3. GET Parameters for Entitlement Configuration in section 2.3
+         * HTTP GET method Parameters.
+         * @hide
+         */
+        public static final String KEY_ENTITLEMENT_VERSION_INT =
+                KEY_PREFIX + "entitlement_version_int";
+
+        /**
+         * Controls the service entitlement status when receiving the VERS characteristic
+         * with both version and validity set to -1 or -2.
+         * If {@code true}, default service entitlement status is enabled.
+         * If {@code false}, default service entitlement status is disabled.
+         *
+         * Reference: GSMA TS.14-v8 section 2.1, overview
+         * @hide
+         */
+        public static final String KEY_DEFAULT_SERVICE_ENTITLEMENT_STATUS_BOOL =
+                KEY_PREFIX + "default_service_entitlement_status_bool";
+
+        /**
+         * Indicates if UE can skip service entitlement check when the user turns on Wi-Fi Calling.
+         * UE still shows Wi-Fi Calling emergency address update web view when the user clicks
+         * "Update Emergency Address" on the WiFi calling setting.
+         *
+         * Note: this is effective only if the {@link #KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING}
+         * is set to this app.
+         * @hide
+         */
+        public static final String KEY_SKIP_WFC_ACTIVATION_BOOL =
+                KEY_PREFIX + "skip_wfc_activation_bool";
+
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putString(KEY_ENTITLEMENT_SERVER_URL_STRING, "");
             defaults.putString(KEY_FCM_SENDER_ID_STRING, "");
             defaults.putBoolean(KEY_SHOW_VOWIFI_WEBVIEW_BOOL, false);
             defaults.putBoolean(KEY_IMS_PROVISIONING_BOOL, false);
+            defaults.putBoolean(KEY_DEFAULT_SERVICE_ENTITLEMENT_STATUS_BOOL, false);
+            defaults.putBoolean(KEY_SKIP_WFC_ACTIVATION_BOOL, false);
+            defaults.putInt(KEY_ENTITLEMENT_VERSION_INT, 2);
             return defaults;
         }
     }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 8679bd4..44d3fca 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -29,6 +29,7 @@
 import android.os.Parcelable;
 import android.provider.Telephony;
 import android.provider.Telephony.Carriers;
+import android.provider.Telephony.Carriers.EditStatus;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -37,6 +38,7 @@
 import android.util.Log;
 
 import com.android.internal.telephony.flags.Flags;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.telephony.Rlog;
 
 import java.lang.annotation.Retention;
@@ -571,6 +573,13 @@
     private final boolean mEsimBootstrapProvisioning;
 
     /**
+     * The APN edited status.
+     *
+     * Note it is intended not using this field for {@link #equals(Object)} or {@link #hashCode()}.
+     */
+    private final @EditStatus int mEditedStatus;
+
+    /**
      * Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
      * up by this APN setting. Note this value will only be used when MTU size is not provided
      * in {@code DataCallResponse#getMtuV4()} during network bring up.
@@ -992,6 +1001,22 @@
         return mEsimBootstrapProvisioning;
     }
 
+    /**
+     * @return APN edited status. APN could be added/edited/deleted by a user or carrier.
+     *
+     * @see Carriers#UNEDITED
+     * @see Carriers#USER_EDITED
+     * @see Carriers#USER_DELETED
+     * @see Carriers#CARRIER_EDITED
+     * @see Carriers#CARRIER_DELETED
+     *
+     * @hide
+     */
+    @EditStatus
+    public int getEditedStatus() {
+        return mEditedStatus;
+    }
+
     private ApnSetting(Builder builder) {
         this.mEntryName = builder.mEntryName;
         this.mApnName = builder.mApnName;
@@ -1030,6 +1055,7 @@
         this.mAlwaysOn = builder.mAlwaysOn;
         this.mInfrastructureBitmask = builder.mInfrastructureBitmask;
         this.mEsimBootstrapProvisioning = builder.mEsimBootstrapProvisioning;
+        this.mEditedStatus = builder.mEditedStatus;
     }
 
     /**
@@ -1113,6 +1139,8 @@
                         Telephony.Carriers.INFRASTRUCTURE_BITMASK)))
                 .setEsimBootstrapProvisioning(cursor.getInt(
                         cursor.getColumnIndexOrThrow(Carriers.ESIM_BOOTSTRAP_PROVISIONING)) == 1)
+                .setEditedStatus(cursor.getInt(
+                        cursor.getColumnIndexOrThrow(Carriers.EDITED_STATUS)))
                 .buildWithoutCheck();
     }
 
@@ -1154,6 +1182,7 @@
                 .setAlwaysOn(apn.mAlwaysOn)
                 .setInfrastructureBitmask(apn.mInfrastructureBitmask)
                 .setEsimBootstrapProvisioning(apn.mEsimBootstrapProvisioning)
+                .setEditedStatus(apn.mEditedStatus)
                 .buildWithoutCheck();
     }
 
@@ -1202,6 +1231,7 @@
         sb.append(", ").append(mInfrastructureBitmask);
         sb.append(", ").append(Objects.hash(mUser, mPassword));
         sb.append(", ").append(mEsimBootstrapProvisioning);
+        sb.append(", ").append(TelephonyUtils.apnEditedStatusToString(mEditedStatus));
         return sb.toString();
     }
 
@@ -1748,6 +1778,7 @@
         dest.writeBoolean(mAlwaysOn);
         dest.writeInt(mInfrastructureBitmask);
         dest.writeBoolean(mEsimBootstrapProvisioning);
+        dest.writeInt(mEditedStatus);
     }
 
     private static ApnSetting readFromParcel(Parcel in) {
@@ -1785,6 +1816,7 @@
                 .setAlwaysOn(in.readBoolean())
                 .setInfrastructureBitmask(in.readInt())
                 .setEsimBootstrapProvisioning(in.readBoolean())
+                .setEditedStatus(in.readInt())
                 .buildWithoutCheck();
     }
 
@@ -1868,6 +1900,7 @@
         private boolean mAlwaysOn;
         private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR | INFRASTRUCTURE_SATELLITE;
         private boolean mEsimBootstrapProvisioning;
+        private @EditStatus int mEditedStatus = Carriers.UNEDITED;
 
         /**
          * Default constructor for Builder.
@@ -2310,6 +2343,8 @@
          *
          * @param esimBootstrapProvisioning {@code true} if the APN is used for eSIM bootstrap
          * provisioning, {@code false} otherwise.
+         *
+         * @return The builder.
          * @hide
          */
         @NonNull
@@ -2319,6 +2354,26 @@
         }
 
         /**
+         * Set the edited status. APN could be added/edited/deleted by a user or carrier.
+         *
+         * @param editedStatus The APN edited status
+         * @return The builder.
+         *
+         * @see Carriers#UNEDITED
+         * @see Carriers#USER_EDITED
+         * @see Carriers#USER_DELETED
+         * @see Carriers#CARRIER_EDITED
+         * @see Carriers#CARRIER_DELETED
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setEditedStatus(@EditStatus int editedStatus) {
+            this.mEditedStatus = editedStatus;
+            return this;
+        }
+
+        /**
          * Builds {@link ApnSetting} from this builder.
          *
          * @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index b429407..d44a43e 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -37,6 +37,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * A parcelable class that wraps and retrieves the information of number, service category(s) and
@@ -300,8 +301,8 @@
         dest.writeInt(mEmergencyCallRouting);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<EmergencyNumber> CREATOR =
-            new Parcelable.Creator<EmergencyNumber>() {
+    public static final @NonNull Creator<EmergencyNumber> CREATOR =
+            new Creator<EmergencyNumber>() {
                 @Override
                 public EmergencyNumber createFromParcel(Parcel in) {
                     return new EmergencyNumber(in);
@@ -500,12 +501,94 @@
 
     @Override
     public String toString() {
-        return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
-                + "|Mnc-" + mMnc
-                + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
-                + "|Urns-" + mEmergencyUrns
-                + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
-                + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
+        return String.format("[EmergencyNumber: %s, countryIso=%s, mnc=%s, src=%s, routing=%s, "
+                        + "categories=%s, urns=%s]",
+                mNumber,
+                mCountryIso,
+                mMnc,
+                sourceBitmaskToString(mEmergencyNumberSourceBitmask),
+                routingToString(mEmergencyCallRouting),
+                categoriesToString(mEmergencyServiceCategoryBitmask),
+                (mEmergencyUrns == null ? "" :
+                        mEmergencyUrns.stream().collect(Collectors.joining(","))));
+    }
+
+    /**
+     * @param categories emergency service category bitmask
+     * @return loggable string describing the category bitmask
+     */
+    private String categoriesToString(@EmergencyServiceCategories int categories) {
+        StringBuilder sb = new StringBuilder();
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_AIEC) == EMERGENCY_SERVICE_CATEGORY_AIEC) {
+            sb.append("auto ");
+        }
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_AMBULANCE)
+                == EMERGENCY_SERVICE_CATEGORY_AMBULANCE) {
+            sb.append("ambulance ");
+        }
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE)
+                == EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE) {
+            sb.append("fire ");
+        }
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD)
+                == EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD) {
+            sb.append("marine ");
+        }
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE)
+                == EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE) {
+            sb.append("mountain ");
+        }
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_POLICE) == EMERGENCY_SERVICE_CATEGORY_POLICE) {
+            sb.append("police ");
+        }
+        if ((categories & EMERGENCY_SERVICE_CATEGORY_MIEC) == EMERGENCY_SERVICE_CATEGORY_MIEC) {
+            sb.append("manual ");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * @param routing emergency call routing type
+     * @return loggable string describing the routing type.
+     */
+    private String routingToString(@EmergencyCallRouting int routing) {
+        return switch(routing) {
+            case EMERGENCY_CALL_ROUTING_EMERGENCY -> "emergency";
+            case EMERGENCY_CALL_ROUTING_NORMAL -> "normal";
+            case EMERGENCY_CALL_ROUTING_UNKNOWN -> "unknown";
+            default -> "🤷";
+        };
+    }
+
+    /**
+     * Builds a string describing the sources for an emergency number.
+     * @param sourceBitmask the source bitmask
+     * @return loggable string describing the sources.
+     */
+    private String sourceBitmaskToString(@EmergencyNumberSources int sourceBitmask) {
+        StringBuilder sb = new StringBuilder();
+        if ((sourceBitmask & EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING)
+                == EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING) {
+            sb.append("net ");
+        }
+        if ((sourceBitmask & EMERGENCY_NUMBER_SOURCE_SIM) == EMERGENCY_NUMBER_SOURCE_SIM) {
+            sb.append("sim ");
+        }
+        if ((sourceBitmask & EMERGENCY_NUMBER_SOURCE_DATABASE)
+                == EMERGENCY_NUMBER_SOURCE_DATABASE) {
+            sb.append("db ");
+        }
+        if ((sourceBitmask & EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG)
+                == EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG) {
+            sb.append("mdm ");
+        }
+        if ((sourceBitmask & EMERGENCY_NUMBER_SOURCE_DEFAULT) == EMERGENCY_NUMBER_SOURCE_DEFAULT) {
+            sb.append("def ");
+        }
+        if ((sourceBitmask & EMERGENCY_NUMBER_SOURCE_TEST) == EMERGENCY_NUMBER_SOURCE_TEST) {
+            sb.append("tst ");
+        }
+        return sb.toString();
     }
 
     @Override
diff --git a/tests/BootImageProfileTest/AndroidTest.xml b/tests/BootImageProfileTest/AndroidTest.xml
index 7e97fa3..9b527dc 100644
--- a/tests/BootImageProfileTest/AndroidTest.xml
+++ b/tests/BootImageProfileTest/AndroidTest.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for BootImageProfileTest">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
      <!-- do not use DeviceSetup#set-property because it reboots the device b/136200738.
          furthermore the changes in /data/local.prop don't actually seem to get picked up.
     -->
diff --git a/tests/EnforcePermission/Android.bp b/tests/EnforcePermission/Android.bp
index 719a898..6a5add0 100644
--- a/tests/EnforcePermission/Android.bp
+++ b/tests/EnforcePermission/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_responsible_apis",
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
diff --git a/tests/EnforcePermission/perf-app/Android.bp b/tests/EnforcePermission/perf-app/Android.bp
index b494bb7..6d04fdc 100644
--- a/tests/EnforcePermission/perf-app/Android.bp
+++ b/tests/EnforcePermission/perf-app/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_responsible_apis",
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
diff --git a/tests/EnforcePermission/service-app/Android.bp b/tests/EnforcePermission/service-app/Android.bp
index 7878215..8910f2a 100644
--- a/tests/EnforcePermission/service-app/Android.bp
+++ b/tests/EnforcePermission/service-app/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_responsible_apis",
     // 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"
diff --git a/tests/EnforcePermission/test-app/Android.bp b/tests/EnforcePermission/test-app/Android.bp
index cd53854..065ab33 100644
--- a/tests/EnforcePermission/test-app/Android.bp
+++ b/tests/EnforcePermission/test-app/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_responsible_apis",
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
diff --git a/tests/FlickerTests/AppClose/Android.bp b/tests/FlickerTests/AppClose/Android.bp
index 93fdd65..d14a178 100644
--- a/tests/FlickerTests/AppClose/Android.bp
+++ b/tests/FlickerTests/AppClose/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_windowing_animations_transitions",
     // 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"
diff --git a/tests/FlickerTests/IME/Android.bp b/tests/FlickerTests/IME/Android.bp
index 1141e5f..b024471 100644
--- a/tests/FlickerTests/IME/Android.bp
+++ b/tests/FlickerTests/IME/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_input_method_framework",
     // 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"
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 47a1619..99e8ef5 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -85,7 +85,6 @@
                     val visibleAreas =
                         imeSnapshotLayers
                             .mapNotNull { imeSnapshotLayer -> imeSnapshotLayer.layer.visibleRegion }
-                            .toTypedArray()
                     val imeVisibleRegion = RegionSubject(visibleAreas, timestamp)
                     val appVisibleRegion = it.visibleRegion(imeTestApp)
                     if (imeVisibleRegion.region.isNotEmpty) {
diff --git a/tests/FlickerTests/Rotation/Android.bp b/tests/FlickerTests/Rotation/Android.bp
index 233a276..b3eb934 100644
--- a/tests/FlickerTests/Rotation/Android.bp
+++ b/tests/FlickerTests/Rotation/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_windowing_animations_transitions",
     // 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"
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 4032121..1abb8c2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -281,7 +281,6 @@
             val visibleAreas =
                 snapshotLayers
                     .mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion }
-                    .toTypedArray()
             val snapshotRegion = RegionSubject(visibleAreas, it.timestamp)
             val appVisibleRegion = it.visibleRegion(component)
             // Verify the size of snapshotRegion covers appVisibleRegion exactly in animation.
diff --git a/tests/FsVerityTest/Android.bp b/tests/FsVerityTest/Android.bp
index 53606a3..02268c3 100644
--- a/tests/FsVerityTest/Android.bp
+++ b/tests/FsVerityTest/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_platform_security",
     // 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"
diff --git a/tests/FsVerityTest/FsVerityTestApp/Android.bp b/tests/FsVerityTest/FsVerityTestApp/Android.bp
index 43da3ff..71a7e4f 100644
--- a/tests/FsVerityTest/FsVerityTestApp/Android.bp
+++ b/tests/FsVerityTest/FsVerityTestApp/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_platform_security",
     // 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"
diff --git a/tests/FsVerityTest/block_device_writer/Android.bp b/tests/FsVerityTest/block_device_writer/Android.bp
index 0002447d..2a337de 100644
--- a/tests/FsVerityTest/block_device_writer/Android.bp
+++ b/tests/FsVerityTest/block_device_writer/Android.bp
@@ -15,6 +15,7 @@
 // This is a cc_test just because it supports test_suites. This should be converted to something
 // like cc_binary_test_helper once supported, thus auto_gen_config:false below.
 package {
+    default_team: "trendy_team_platform_security",
     // 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"
diff --git a/tests/FsVerityTest/testdata/Android.bp b/tests/FsVerityTest/testdata/Android.bp
index 2d578d3..21b63e7 100644
--- a/tests/FsVerityTest/testdata/Android.bp
+++ b/tests/FsVerityTest/testdata/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_platform_security",
     // 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"
diff --git a/tests/HandwritingIme/Android.bp b/tests/HandwritingIme/Android.bp
index 1f552bf..0d2422e 100644
--- a/tests/HandwritingIme/Android.bp
+++ b/tests/HandwritingIme/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_method_framework",
     // 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"
diff --git a/tests/InputScreenshotTest/Android.bp b/tests/InputScreenshotTest/Android.bp
index 83ced2c..927b101 100644
--- a/tests/InputScreenshotTest/Android.bp
+++ b/tests/InputScreenshotTest/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_input_framework",
     // 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"
diff --git a/tests/InputScreenshotTest/assets/phone/light_landscape_layout-preview.png b/tests/InputScreenshotTest/assets/phone/light_landscape_layout-preview.png
index 70e4a71..443de8e 100644
--- a/tests/InputScreenshotTest/assets/phone/light_landscape_layout-preview.png
+++ b/tests/InputScreenshotTest/assets/phone/light_landscape_layout-preview.png
Binary files differ
diff --git a/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-ansi.png b/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-ansi.png
index 502c1b4..cb69c0e 100644
--- a/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-ansi.png
+++ b/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-ansi.png
Binary files differ
diff --git a/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-jis.png b/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-jis.png
index 591b2fa..1c6d1b3 100644
--- a/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-jis.png
+++ b/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview-jis.png
Binary files differ
diff --git a/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview.png b/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview.png
index 0137a85..c51da05 100644
--- a/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview.png
+++ b/tests/InputScreenshotTest/assets/phone/light_portrait_layout-preview.png
Binary files differ
diff --git a/tests/InputScreenshotTest/assets/tablet/dark_portrait_layout-preview.png b/tests/InputScreenshotTest/assets/tablet/dark_portrait_layout-preview.png
index 37a91e1..ab23401 100644
--- a/tests/InputScreenshotTest/assets/tablet/dark_portrait_layout-preview.png
+++ b/tests/InputScreenshotTest/assets/tablet/dark_portrait_layout-preview.png
Binary files differ
diff --git a/tests/InputScreenshotTest/robotests/Android.bp b/tests/InputScreenshotTest/robotests/Android.bp
index 912f4b80..384f58a 100644
--- a/tests/InputScreenshotTest/robotests/Android.bp
+++ b/tests/InputScreenshotTest/robotests/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_input_framework",
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
diff --git a/tests/Internal/src/com/android/internal/protolog/OWNERS b/tests/Internal/src/com/android/internal/protolog/OWNERS
new file mode 100644
index 0000000..18cf2be
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/OWNERS
@@ -0,0 +1,3 @@
+# ProtoLog owners
+# Bug component: 1157642
+include platform/development:/tools/winscope/OWNERS
diff --git a/tests/graphics/HwAccelerationTest/Android.bp b/tests/graphics/HwAccelerationTest/Android.bp
index 51848f2..d95a9b9 100644
--- a/tests/graphics/HwAccelerationTest/Android.bp
+++ b/tests/graphics/HwAccelerationTest/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_android_core_graphics_stack",
     // 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"
diff --git a/tests/graphics/HwAccelerationTest/jni/Android.bp b/tests/graphics/HwAccelerationTest/jni/Android.bp
index 8edddab..76e4f9c 100644
--- a/tests/graphics/HwAccelerationTest/jni/Android.bp
+++ b/tests/graphics/HwAccelerationTest/jni/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_android_core_graphics_stack",
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
diff --git a/tests/graphics/RenderThreadTest/Android.bp b/tests/graphics/RenderThreadTest/Android.bp
index b18b04e..d6d85e8 100644
--- a/tests/graphics/RenderThreadTest/Android.bp
+++ b/tests/graphics/RenderThreadTest/Android.bp
@@ -1,4 +1,5 @@
 package {
+    default_team: "trendy_team_android_core_graphics_stack",
     // 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"
diff --git a/tests/graphics/SilkFX/Android.bp b/tests/graphics/SilkFX/Android.bp
index 1e467db..b149cf3 100644
--- a/tests/graphics/SilkFX/Android.bp
+++ b/tests/graphics/SilkFX/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_android_core_graphics_stack",
     // 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"
diff --git a/tests/graphics/VectorDrawableTest/Android.bp b/tests/graphics/VectorDrawableTest/Android.bp
index 9da7c5f..0042a43 100644
--- a/tests/graphics/VectorDrawableTest/Android.bp
+++ b/tests/graphics/VectorDrawableTest/Android.bp
@@ -15,6 +15,7 @@
 //
 
 package {
+    default_team: "trendy_team_android_gpu",
     // 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"
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp b/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp
index afaa3f0..8d05a97 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/Android.bp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 package {
+    default_team: "trendy_team_input_method_framework",
     default_applicable_licenses: ["frameworks_base_license"],
 }