Merge "Remove WindowConfiguration.setBounds and getBounds annotations" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 26b0263..2137f47 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -309,6 +309,7 @@
     field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
+    field public static final String REPORT_USAGE_STATS = "android.permission.REPORT_USAGE_STATS";
     field @Deprecated public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
     field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fbb97ff..cbbf4e0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -868,10 +868,6 @@
             @Override
             public VirtualDeviceManager createService(ContextImpl ctx)
                     throws ServiceNotFoundException {
-                if (!ctx.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_COMPANION_DEVICE_SETUP)) {
-                    return null;
-                }
                 if (!ctx.getResources().getBoolean(R.bool.config_enableVirtualDeviceManager)) {
                     return null;
                 }
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index ecf16439..2a10ed1 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1106,6 +1106,7 @@
      * <p><em>This method is only for use by the system</em>
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.REPORT_USAGE_STATS)
     public void reportUserInteraction(@NonNull String packageName, int userId) {
         try {
             mService.reportUserInteraction(packageName, userId);
@@ -1396,6 +1397,7 @@
      * {@link UsageEvents}
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.REPORT_USAGE_STATS)
     public void reportChooserSelection(String packageName, int userId, String contentType,
                                        String[] annotations, String action) {
         try {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f3194b4..dd1a499 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6099,6 +6099,10 @@
         android:protectionLevel="signature|privileged|development|appop|retailDemo" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
+    <!-- @SystemApi @hide Allows trusted system components to report events to UsageStatsManager -->
+    <permission android:name="android.permission.REPORT_USAGE_STATS"
+                android:protectionLevel="signature|module" />
+
     <!-- Allows an application to query broadcast response stats (see
          {@link android.app.usage.BroadcastResponseStats}).
          @SystemApi
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index 0f467b9..8b56336 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -15,7 +15,7 @@
 #
 
 [versions]
-agp = "8.1.0"
+agp = "8.1.1"
 compose-compiler = "1.5.1"
 dexmaker-mockito = "2.28.3"
 kotlin = "1.9.0"
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
index c1962a7..033e24c 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
index 5b0ac44..da04f42 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
@@ -16,6 +16,8 @@
 
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/packages/SettingsLib/Spa/gradlew b/packages/SettingsLib/Spa/gradlew
index aeb74cb..fcb6fca 100755
--- a/packages/SettingsLib/Spa/gradlew
+++ b/packages/SettingsLib/Spa/gradlew
@@ -130,10 +130,13 @@
     fi
 else
     JAVACMD=java
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
+    fi
 fi
 
 # Increase the maximum file descriptors if we can.
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 84198de..b810511 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -63,7 +63,7 @@
     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.7.0-rc01")
+    api("androidx.navigation:navigation-compose:2.7.1")
     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/framework/common/SettingsEntryBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
index 97d8de3..0d489e8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
@@ -147,19 +147,20 @@
             return create(entryName, owner).setLink(toPage = owner)
         }
 
-        fun create(owner: SettingsPage, entryName: String, label: String? = null):
-            SettingsEntryBuilder {
-            return SettingsEntryBuilder(entryName, owner).setLabel(label ?: entryName)
-        }
+        fun create(
+            owner: SettingsPage,
+            entryName: String,
+            label: String = entryName,
+        ): SettingsEntryBuilder = SettingsEntryBuilder(entryName, owner).setLabel(label)
 
-        fun createInject(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
-            val label = label ?: "${INJECT_ENTRY_LABEL}_${owner.displayName}"
-            return createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
-        }
+        fun createInject(
+            owner: SettingsPage,
+            label: String = "${INJECT_ENTRY_LABEL}_${owner.displayName}",
+        ): SettingsEntryBuilder = createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
 
-        fun createRoot(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
-            val label = label ?: "${ROOT_ENTRY_LABEL}_${owner.displayName}"
-            return createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
-        }
+        fun createRoot(
+            owner: SettingsPage,
+            label: String = "${ROOT_ENTRY_LABEL}_${owner.displayName}",
+        ): SettingsEntryBuilder = createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
index b809c0f..3496f02 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
@@ -64,8 +64,8 @@
         }
     }
 
-    override fun onChanged(slice: Slice?) {
-        val uri = slice?.uri ?: return
+    override fun onChanged(value: Slice?) {
+        val uri = value?.uri ?: return
         Log.d(TAG, "onChanged: $uri")
         context?.contentResolver?.notifyChange(uri, null)
     }
@@ -74,4 +74,4 @@
         Log.d(TAG, "onCreateSliceProvider")
         return true
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
index cff1c0c..ee24a09 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
@@ -17,7 +17,7 @@
 package com.android.settingslib.spa.slice.presenter
 
 import android.net.Uri
-import androidx.compose.material3.Divider
+import androidx.compose.material3.HorizontalDivider
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
@@ -34,7 +34,7 @@
         SliceLiveData.fromUri(context, sliceUri)
     }
 
-    Divider()
+    HorizontalDivider()
     AndroidView(
         factory = { localContext ->
             val view = SliceView(localContext)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
index 6135203..6330ddf 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
@@ -24,7 +24,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
-import androidx.compose.material3.Divider
+import androidx.compose.material3.HorizontalDivider
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.ui.Alignment
@@ -105,7 +105,7 @@
         BaseLayout(
             title = "Title",
             subTitle = {
-                Divider(thickness = 10.dp)
+                HorizontalDivider(thickness = 10.dp)
             }
         )
     }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 67f4418..d437e35 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -99,8 +99,8 @@
                 .fillMaxSize(),
         ) {
             content(
-                bottomPadding = paddingValues.calculateBottomPadding(),
-                searchQuery = remember {
+                paddingValues.calculateBottomPadding(),
+                remember {
                     derivedStateOf { if (isSearchMode) viewModel.searchQuery.text else "" }
                 },
             )
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bd3b83e..ffe28a6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -167,6 +167,7 @@
     <uses-permission android:name="android.permission.FORCE_BACK" />
     <uses-permission android:name="android.permission.BATTERY_STATS" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+    <uses-permission android:name="android.permission.REPORT_USAGE_STATS" />
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
index 25269dc..44c4105 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
@@ -78,6 +78,7 @@
         modifier = modifier,
         enabled = enabled,
         content = content,
+        colors = textButtonColors(),
     )
 }
 
@@ -85,26 +86,29 @@
 
 @Composable
 private fun filledButtonColors(): ButtonColors {
-    val colors = LocalAndroidColorScheme.current.deprecated
+    val colors = LocalAndroidColorScheme.current
     return ButtonDefaults.buttonColors(
-        containerColor = colors.colorAccentPrimary,
-        contentColor = colors.textColorOnAccent,
+        containerColor = colors.primary,
+        contentColor = colors.onPrimary,
     )
 }
 
 @Composable
 private fun outlineButtonColors(): ButtonColors {
-    val colors = LocalAndroidColorScheme.current.deprecated
     return ButtonDefaults.outlinedButtonColors(
-        contentColor = colors.textColorPrimary,
+        contentColor = LocalAndroidColorScheme.current.onSurface,
     )
 }
 
 @Composable
 private fun outlineButtonBorder(): BorderStroke {
-    val colors = LocalAndroidColorScheme.current.deprecated
     return BorderStroke(
         width = 1.dp,
-        color = colors.colorAccentPrimaryVariant,
+        color = LocalAndroidColorScheme.current.primary,
     )
 }
+
+@Composable
+private fun textButtonColors(): ButtonColors {
+    return ButtonDefaults.textButtonColors(contentColor = LocalAndroidColorScheme.current.primary)
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
new file mode 100644
index 0000000..48f40e7
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.dialog.ui.composable
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ProvideTextStyle
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.android.compose.theme.LocalAndroidColorScheme
+
+/**
+ * The content of an AlertDialog which can be used together with
+ * [SystemUIDialogFactory.create][com.android.systemui.statusbar.phone.create] to create an alert
+ * dialog in Compose.
+ *
+ * @see com.android.systemui.statusbar.phone.create
+ */
+@Composable
+fun AlertDialogContent(
+    title: @Composable () -> Unit,
+    content: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    icon: (@Composable () -> Unit)? = null,
+    positiveButton: (@Composable () -> Unit)? = null,
+    negativeButton: (@Composable () -> Unit)? = null,
+    neutralButton: (@Composable () -> Unit)? = null,
+) {
+    Column(
+        modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(DialogPaddings),
+        horizontalAlignment = Alignment.CenterHorizontally,
+    ) {
+        // Icon.
+        if (icon != null) {
+            val defaultSize = 32.dp
+            Box(
+                Modifier.defaultMinSize(minWidth = defaultSize, minHeight = defaultSize),
+                propagateMinConstraints = true,
+            ) {
+                val iconColor = LocalAndroidColorScheme.current.primary
+                CompositionLocalProvider(LocalContentColor provides iconColor) { icon() }
+            }
+
+            Spacer(Modifier.height(16.dp))
+        }
+
+        // Title.
+        val titleColor = LocalAndroidColorScheme.current.onSurface
+        CompositionLocalProvider(LocalContentColor provides titleColor) {
+            ProvideTextStyle(
+                MaterialTheme.typography.headlineSmall.copy(textAlign = TextAlign.Center)
+            ) {
+                title()
+            }
+        }
+        Spacer(Modifier.height(16.dp))
+
+        // Content.
+        val contentColor = LocalAndroidColorScheme.current.onSurfaceVariant
+        Box(Modifier.defaultMinSize(minHeight = 48.dp)) {
+            CompositionLocalProvider(LocalContentColor provides contentColor) {
+                ProvideTextStyle(
+                    MaterialTheme.typography.bodyMedium.copy(textAlign = TextAlign.Center)
+                ) {
+                    content()
+                }
+            }
+        }
+        Spacer(Modifier.height(32.dp))
+
+        // Buttons.
+        // TODO(b/283817398): If there is not enough space, the buttons should automatically stack
+        // as shown in go/sysui-dialog-styling.
+        if (positiveButton != null || negativeButton != null || neutralButton != null) {
+            Row(Modifier.fillMaxWidth()) {
+                if (neutralButton != null) {
+                    neutralButton()
+                    Spacer(Modifier.width(8.dp))
+                }
+
+                Spacer(Modifier.weight(1f))
+
+                if (negativeButton != null) {
+                    negativeButton()
+                }
+
+                if (positiveButton != null) {
+                    if (negativeButton != null) {
+                        Spacer(Modifier.width(8.dp))
+                    }
+
+                    positiveButton()
+                }
+            }
+        }
+    }
+}
+
+private val DialogPaddings = PaddingValues(start = 24.dp, end = 24.dp, top = 24.dp, bottom = 18.dp)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
new file mode 100644
index 0000000..5d6dd3b
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.phone
+
+import android.content.Context
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.ComposeView
+import com.android.compose.theme.PlatformTheme
+
+/**
+ * Create a [SystemUIDialog] with the given [content].
+ *
+ * Note that the returned dialog will already have a background so the content should not draw an
+ * additional background.
+ *
+ * Example:
+ * ```
+ * val dialog = systemUiDialogFactory.create {
+ *   AlertDialogContent(
+ *     title = { Text("My title") },
+ *     content = { Text("My content") },
+ *   )
+ * }
+ *
+ * dialogLaunchAnimator.showFromView(dialog, viewThatWasClicked)
+ * ```
+ *
+ * @param context the [Context] in which the dialog will be constructed.
+ * @param dismissOnDeviceLock whether the dialog should be automatically dismissed when the device
+ *   is locked (true by default).
+ */
+fun SystemUIDialogFactory.create(
+    context: Context = this.applicationContext,
+    dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
+    content: @Composable (SystemUIDialog) -> Unit,
+): ComponentSystemUIDialog {
+    val dialog = create(context, dismissOnDeviceLock)
+
+    // Create the dialog so that it is properly constructed before we set the Compose content.
+    // Otherwise, the ComposeView won't render properly.
+    dialog.create()
+
+    // Set the content. Note that the background of the dialog is drawn on the DecorView of the
+    // dialog directly, which makes it automatically work nicely with DialogLaunchAnimator.
+    dialog.setContentView(
+        ComposeView(context).apply {
+            setContent {
+                PlatformTheme {
+                    val defaultContentColor = MaterialTheme.colorScheme.onSurfaceVariant
+                    CompositionLocalProvider(LocalContentColor provides defaultContentColor) {
+                        content(dialog)
+                    }
+                }
+            }
+        }
+    )
+
+    return dialog
+}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2dc1b45..62c4424 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -857,6 +857,8 @@
 
     <dimen name="keyguard_security_container_padding_top">20dp</dimen>
 
+    <dimen name="keyguard_translate_distance_on_swipe_up">-200dp</dimen>
+
     <dimen name="keyguard_indication_margin_bottom">32dp</dimen>
     <dimen name="lock_icon_margin_bottom">74dp</dimen>
     <dimen name="ambient_indication_margin_bottom">71dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 04eae64..579358f 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -212,6 +212,8 @@
     <item type="id" name="keyguard_indication_text" />
     <item type="id" name="keyguard_indication_text_bottom" />
     <item type="id" name="nssl_guideline" />
+    <item type="id" name="nssl_top_barrier" />
+    <item type="id" name="nssl_bottom_barrier" />
     <item type="id" name="split_shade_guideline" />
     <item type="id" name="lock_icon" />
     <item type="id" name="lock_icon_bg" />
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
new file mode 100644
index 0000000..b2bc06f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.common.shared.model
+
+/** Positioning info for the shared notification container */
+data class SharedNotificationContainerPosition(
+    val top: Float = 0f,
+    val bottom: Float = 0f,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index c0d1951..b8de8d8 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -43,6 +43,9 @@
     val scaleForResolution: Flow<Float>
 
     fun getResolutionScale(): Float
+
+    /** Convience to context.resources.getDimensionPixelSize() */
+    fun getDimensionPixelSize(id: Int): Int
 }
 
 @ExperimentalCoroutinesApi
@@ -115,4 +118,8 @@
         }
         return 1f
     }
+
+    override fun getDimensionPixelSize(id: Int): Int {
+        return context.resources.getDimensionPixelSize(id)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d67c5fc..e9a539f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -223,7 +223,7 @@
     // TODO(b/291710220): Tracking bug.
     @JvmField
     val WALLPAPER_PICKER_PAGE_TRANSITIONS =
-        unreleasedFlag("wallpaper_picker_page_transitions")
+        unreleasedFlag("wallpaper_picker_page_transitions", teamfood = true)
 
     /** Add "Apply" button to wall paper picker's grid preview page. */
     // TODO(b/294866904): Tracking bug.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 9b323ee..1cd8795 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -51,6 +51,7 @@
 import com.android.systemui.shade.NotificationShadeWindowView
 import com.android.systemui.statusbar.KeyguardIndicationController
 import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
@@ -90,6 +91,7 @@
     private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
     private val communalWidgetViewModel: CommunalWidgetViewModel,
     private val communalWidgetViewAdapter: CommunalWidgetViewAdapter,
+    private val notificationStackScrollerLayoutController: NotificationStackScrollLayoutController,
 ) : CoreStartable {
 
     private var rootViewHandle: DisposableHandle? = null
@@ -131,6 +133,7 @@
             SharedNotificationContainerBinder.bind(
                 sharedNotificationContainer,
                 sharedNotificationContainerViewModel,
+                notificationStackScrollerLayoutController,
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ed84884..e13f675 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -19,10 +19,14 @@
 
 import android.app.StatusBarManager
 import android.graphics.Point
+import android.util.MathUtils
+import com.android.app.animation.Interpolators
+import com.android.systemui.R
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.Position
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
 import com.android.systemui.common.ui.data.repository.ConfigurationRepository
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
@@ -38,12 +42,14 @@
 import com.android.systemui.keyguard.shared.model.ScreenModel
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -51,6 +57,7 @@
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
 
@@ -66,7 +73,11 @@
     featureFlags: FeatureFlags,
     bouncerRepository: KeyguardBouncerRepository,
     configurationRepository: ConfigurationRepository,
+    shadeRepository: ShadeRepository,
 ) {
+    /** Position information for the shared notification container. */
+    val sharedNotificationContainerPosition =
+        MutableStateFlow(SharedNotificationContainerPosition())
     /**
      * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
      * all.
@@ -196,6 +207,22 @@
 
     val keyguardAlpha: Flow<Float> = repository.keyguardAlpha
 
+    val keyguardTranslationY: Flow<Float> =
+        configurationChange.flatMapLatest {
+            val translationDistance =
+                configurationRepository.getDimensionPixelSize(
+                    R.dimen.keyguard_translate_distance_on_swipe_up
+                )
+            shadeRepository.shadeModel.map {
+                // On swipe up, translate the keyguard to reveal the bouncer
+                MathUtils.lerp(
+                    translationDistance,
+                    0,
+                    Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(it.expansionAmount)
+                )
+            }
+        }
+
     /** Whether to animate the next doze mode transition. */
     val animateDozingTransitions: Flow<Boolean> = repository.animateBottomAreaDozingTransitions
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 19f622b..2814732 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.DrawableRes
 import android.view.View
+import android.view.View.OnLayoutChangeListener
 import android.view.ViewGroup
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
@@ -43,6 +44,9 @@
 /** Bind occludingAppDeviceEntryMessageViewModel to run whenever the keyguard view is attached. */
 @ExperimentalCoroutinesApi
 object KeyguardRootViewBinder {
+
+    private var onLayoutChangeListener: OnLayoutChange? = null
+
     @JvmStatic
     fun bind(
         view: ViewGroup,
@@ -54,8 +58,8 @@
     ): DisposableHandle {
         val disposableHandle =
             view.repeatWhenAttached {
-                if (featureFlags.isEnabled(Flags.FP_LISTEN_OCCLUDING_APPS)) {
-                    repeatOnLifecycle(Lifecycle.State.CREATED) {
+                repeatOnLifecycle(Lifecycle.State.CREATED) {
+                    if (featureFlags.isEnabled(Flags.FP_LISTEN_OCCLUDING_APPS)) {
                         launch {
                             occludingAppDeviceEntryMessageViewModel.message.collect {
                                 biometricMessage ->
@@ -72,10 +76,8 @@
                             }
                         }
                     }
-                }
 
-                if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
-                    repeatOnLifecycle(Lifecycle.State.STARTED) {
+                    if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                         launch {
                             viewModel.keyguardRootViewVisibilityState.collect { visibilityState ->
                                 view.animate().cancel()
@@ -84,16 +86,21 @@
                                 val isOcclusionTransitionRunning =
                                     visibilityState.occlusionTransitionRunning
                                 if (goingToFullShade) {
-                                    view.animate().alpha(0f).setStartDelay(
-                                        keyguardStateController.keyguardFadingAwayDelay
-                                    ).setDuration(
-                                        keyguardStateController.shortenedFadingAwayDuration
-                                    ).setInterpolator(
-                                        Interpolators.ALPHA_OUT
-                                    ).withEndAction { view.visibility = View.GONE }.start()
+                                    view
+                                        .animate()
+                                        .alpha(0f)
+                                        .setStartDelay(
+                                            keyguardStateController.keyguardFadingAwayDelay
+                                        )
+                                        .setDuration(
+                                            keyguardStateController.shortenedFadingAwayDuration
+                                        )
+                                        .setInterpolator(Interpolators.ALPHA_OUT)
+                                        .withEndAction { view.visibility = View.GONE }
+                                        .start()
                                 } else if (
                                     statusBarState == StatusBarState.KEYGUARD ||
-                                    statusBarState == StatusBarState.SHADE_LOCKED
+                                        statusBarState == StatusBarState.SHADE_LOCKED
                                 ) {
                                     view.visibility = View.VISIBLE
                                     if (!isOcclusionTransitionRunning) {
@@ -105,15 +112,30 @@
                             }
                         }
 
+                        launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
+                    }
+
+                    if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
                         launch {
-                            viewModel.alpha.collect { alpha ->
-                                view.alpha = alpha
+                            viewModel.translationY.collect {
+                                val statusView =
+                                    view.requireViewById<View>(R.id.keyguard_status_view)
+                                statusView.translationY = it
                             }
                         }
                     }
                 }
             }
-        return disposableHandle
+
+        onLayoutChangeListener = OnLayoutChange(viewModel)
+        view.addOnLayoutChangeListener(onLayoutChangeListener)
+
+        return object : DisposableHandle {
+            override fun dispose() {
+                disposableHandle.dispose()
+                view.removeOnLayoutChangeListener(onLayoutChangeListener)
+            }
+        }
     }
 
     /**
@@ -122,10 +144,10 @@
     private fun createChipbarInfo(message: String, @DrawableRes icon: Int): ChipbarInfo {
         return ChipbarInfo(
             startIcon =
-            TintedIcon(
-                Icon.Resource(icon, null),
-                ChipbarInfo.DEFAULT_ICON_TINT,
-            ),
+                TintedIcon(
+                    Icon.Resource(icon, null),
+                    ChipbarInfo.DEFAULT_ICON_TINT,
+                ),
             text = Text.Loaded(message),
             endItem = null,
             vibrationEffect = null,
@@ -138,5 +160,31 @@
         )
     }
 
+    private class OnLayoutChange(private val viewModel: KeyguardRootViewModel) :
+        OnLayoutChangeListener {
+        override fun onLayoutChange(
+            v: View,
+            left: Int,
+            top: Int,
+            right: Int,
+            bottom: Int,
+            oldLeft: Int,
+            oldTop: Int,
+            oldRight: Int,
+            oldBottom: Int
+        ) {
+            val ksv = v.findViewById(R.id.keyguard_status_view) as View?
+            val lockIcon = v.findViewById(R.id.lock_icon_view) as View?
+
+            if (ksv != null && lockIcon != null) {
+                // After layout, ensure the notifications are positioned correctly
+                viewModel.onSharedNotificationContainerPositionChanged(
+                    ksv!!.top.toFloat() + ksv!!.height,
+                    lockIcon!!.y
+                )
+            }
+        }
+    }
+
     private const val ID = "occluding_app_device_entry_unlock_msg"
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index 3f319ba..f1f5973 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -18,20 +18,20 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.content.Context
-import android.view.ViewGroup
-import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
-import javax.inject.Inject
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
-import androidx.constraintlayout.widget.ConstraintSet.END
+import com.android.systemui.R
+import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.util.LargeScreenUtils
+import com.android.systemui.util.Utils
+import javax.inject.Inject
 
-class DefaultStatusViewSection @Inject constructor(private val context: Context) :
-    KeyguardSection {
+class DefaultStatusViewSection @Inject constructor(private val context: Context) : KeyguardSection {
     private val statusViewId = R.id.keyguard_status_view
 
     override fun apply(constraintSet: ConstraintSet) {
@@ -41,6 +41,15 @@
             connect(statusViewId, TOP, PARENT_ID, TOP)
             connect(statusViewId, START, PARENT_ID, START)
             connect(statusViewId, END, PARENT_ID, END)
+
+            val margin =
+                if (LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)) {
+                    context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
+                } else {
+                    context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
+                        Utils.getStatusBarHeaderHeightKeyguard(context)
+                }
+            setMargin(statusViewId, TOP, margin)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 92b9ee4..c49af4d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
 import javax.inject.Inject
@@ -57,6 +58,8 @@
             }
         }
 
+    val translationY: Flow<Float> = keyguardInteractor.keyguardTranslationY
+
     /**
      * Puts this view-model in "preview mode", which means it's being used for UI that is rendering
      * the lock screen preview in wallpaper picker / settings and not the real experience on the
@@ -66,4 +69,9 @@
         val newPreviewMode = PreviewMode(true)
         previewMode.value = newPreviewMode
     }
+
+    fun onSharedNotificationContainerPositionChanged(top: Float, bottom: Float) {
+        keyguardInteractor.sharedNotificationContainerPosition.value =
+            SharedNotificationContainerPosition(top, bottom)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 014093d..a41d6e8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -194,6 +194,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
 import com.android.systemui.statusbar.phone.BounceInterpolator;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
@@ -606,7 +607,7 @@
 
     private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
     private final PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
-
+    private final SharedNotificationContainerInteractor mSharedNotificationContainerInteractor;
     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
     private final KeyguardInteractor mKeyguardInteractor;
     private final KeyguardViewConfigurator mKeyguardViewConfigurator;
@@ -772,6 +773,7 @@
             KeyguardLongPressViewModel keyguardLongPressViewModel,
             KeyguardInteractor keyguardInteractor,
             ActivityStarter activityStarter,
+            SharedNotificationContainerInteractor sharedNotificationContainerInteractor,
             KeyguardViewConfigurator keyguardViewConfigurator,
             KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
             KeyguardRootView keyguardRootView) {
@@ -797,6 +799,7 @@
         mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
         mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+        mSharedNotificationContainerInteractor = sharedNotificationContainerInteractor;
         mKeyguardInteractor = keyguardInteractor;
         mKeyguardViewConfigurator = keyguardViewConfigurator;
         mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@@ -1308,15 +1311,17 @@
         // Reset any left over overscroll state. It is a rare corner case but can happen.
         mQsController.setOverScrollAmount(0);
         mScrimController.setNotificationsOverScrollAmount(0);
-        mNotificationStackScrollLayoutController.setOverExpansion(0);
-        mNotificationStackScrollLayoutController.setOverScrollAmount(0);
+        if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            mNotificationStackScrollLayoutController.setOverExpansion(0);
+            mNotificationStackScrollLayoutController.setOverScrollAmount(0);
+        }
 
         // when we switch between split shade and regular shade we want to enforce setting qs to
         // the default state: expanded for split shade and collapsed otherwise
-        if (!isOnKeyguard() && mPanelExpanded) {
+        if (!isKeyguardShowing() && mPanelExpanded) {
             mQsController.setExpanded(mSplitShadeEnabled);
         }
-        if (isOnKeyguard() && mQsController.getExpanded() && mSplitShadeEnabled) {
+        if (isKeyguardShowing() && mQsController.getExpanded() && mSplitShadeEnabled) {
             // In single column keyguard - when you swipe from the top - QS is fully expanded and
             // StatusBarState is KEYGUARD. That state doesn't make sense for split shade,
             // where notifications are always visible and we effectively go to fully expanded
@@ -1327,7 +1332,9 @@
         }
         updateClockAppearance();
         mQsController.updateQsState();
-        mNotificationStackScrollLayoutController.updateFooter();
+        if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            mNotificationStackScrollLayoutController.updateFooter();
+        }
     }
 
     private View reInflateStub(int viewId, int stubId, int layoutId, boolean enabled) {
@@ -1368,10 +1375,6 @@
 
             attachSplitShadeMediaPlayerContainer(
                     keyguardStatusView.findViewById(R.id.status_view_media_container));
-        } else {
-            attachSplitShadeMediaPlayerContainer(
-                    mKeyguardViewConfigurator.getKeyguardRootView()
-                        .findViewById(R.id.status_view_media_container));
         }
 
         // we need to update KeyguardStatusView constraints after reinflating it
@@ -1400,6 +1403,12 @@
 
         updateViewControllers(userAvatarView, keyguardUserSwitcherView);
 
+        if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+            attachSplitShadeMediaPlayerContainer(
+                    mKeyguardViewConfigurator.getKeyguardRootView()
+                        .findViewById(R.id.status_view_media_container));
+        }
+
         if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
             // Update keyguard bottom area
             int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1481,6 +1490,10 @@
             if (SPEW_LOGCAT) Log.d(TAG, "Skipping computeMaxKeyguardNotifications() by request");
         }
 
+        if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            return;
+        }
+
         if (isKeyguardShowing() && !mKeyguardBypassController.getBypassEnabled()) {
             mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
                     mMaxAllowedKeyguardNotifications);
@@ -1552,7 +1565,7 @@
     private void positionClockAndNotifications(boolean forceClockUpdate) {
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
-        boolean onKeyguard = isOnKeyguard();
+        boolean onKeyguard = isKeyguardShowing();
 
         if (onKeyguard || forceClockUpdate) {
             updateClockAppearance();
@@ -1624,8 +1637,10 @@
                 mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
                 mKeyguardStatusViewController.isClockTopAligned());
         mClockPositionAlgorithm.run(mClockPositionResult);
-        mKeyguardStatusViewController.setLockscreenClockY(
-                mClockPositionAlgorithm.getExpandedPreferredClockY());
+        if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            mKeyguardStatusViewController.setLockscreenClockY(
+                    mClockPositionAlgorithm.getExpandedPreferredClockY());
+        }
         if (mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
             mKeyguardInteractor.setClockPosition(
                 mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -1635,9 +1650,12 @@
         }
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
         boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
-        mKeyguardStatusViewController.updatePosition(
-                mClockPositionResult.clockX, mClockPositionResult.clockY,
-                mClockPositionResult.clockScale, animateClock);
+
+        if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            mKeyguardStatusViewController.updatePosition(
+                    mClockPositionResult.clockX, mClockPositionResult.clockY,
+                    mClockPositionResult.clockScale, animateClock);
+        }
         if (mKeyguardQsUserSwitchController != null) {
             mKeyguardQsUserSwitchController.updatePosition(
                     mClockPositionResult.clockX,
@@ -1867,8 +1885,12 @@
         }
         float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
         mKeyguardStatusViewController.setAlpha(alpha);
-        mKeyguardStatusViewController
-            .setTranslationY(mKeyguardOnlyTransitionTranslationY, /* excludeMedia= */true);
+        if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            // TODO (b/296373478) This is for split shade media movement.
+        } else {
+            mKeyguardStatusViewController
+                .setTranslationY(mKeyguardOnlyTransitionTranslationY, /* excludeMedia= */true);
+        }
 
         if (mKeyguardQsUserSwitchController != null) {
             mKeyguardQsUserSwitchController.setAlpha(alpha);
@@ -1980,7 +2002,7 @@
             mQsController.setExpandImmediate(true);
             setShowShelfOnly(true);
         }
-        if (mSplitShadeEnabled && isOnKeyguard()) {
+        if (mSplitShadeEnabled && isKeyguardShowing()) {
             // It's a special case as this method is likely to not be initiated by finger movement
             // but rather called from adb shell or accessibility service.
             // We're using LockscreenShadeTransitionController because on lockscreen that's the
@@ -2024,7 +2046,7 @@
         mQsController.setLastShadeFlingWasExpanding(expand);
         mHeadsUpTouchHelper.notifyFling(!expand);
         mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
-        setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
+        setClosingWithAlphaFadeout(!expand && !isKeyguardShowing() && getFadeoutAlpha() == 1.0f);
         mNotificationStackScrollLayoutController.setPanelFlinging(true);
         if (target == mExpandedHeight && mOverExpansion == 0.0f) {
             // We're at the target and didn't fling and there's no overshoot
@@ -2425,9 +2447,14 @@
     }
 
     void requestScrollerTopPaddingUpdate(boolean animate) {
-        mNotificationStackScrollLayoutController.updateTopPadding(
-                mQsController.calculateNotificationsTopPadding(mIsExpandingOrCollapsing,
-                        getKeyguardNotificationStaticPadding(), mExpandedFraction), animate);
+        float padding = mQsController.calculateNotificationsTopPadding(mIsExpandingOrCollapsing,
+                getKeyguardNotificationStaticPadding(), mExpandedFraction);
+        if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            mSharedNotificationContainerInteractor.setTopPosition(padding);
+        } else {
+            mNotificationStackScrollLayoutController.updateTopPadding(padding, animate);
+        }
+
         if (isKeyguardShowing()
                 && mKeyguardBypassController.getBypassEnabled()) {
             // update the position of the header
@@ -3022,7 +3049,7 @@
             mNotificationStackScrollLayoutController
                     .setExpandingVelocity(getCurrentExpandVelocity());
         }
-        if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
+        if (mKeyguardBypassController.getBypassEnabled() && isKeyguardShowing()) {
             // The expandedHeight is always the full panel Height when bypassing
             expandedHeight = getMaxPanelHeight();
         }
@@ -3033,7 +3060,7 @@
 
     private void updateStatusBarIcons() {
         boolean showIconsWhenExpanded = getExpandedHeight() < getOpeningHeight();
-        if (showIconsWhenExpanded && isOnKeyguard()) {
+        if (showIconsWhenExpanded && isKeyguardShowing()) {
             showIconsWhenExpanded = false;
         }
         if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
@@ -3047,10 +3074,6 @@
         return mBarState;
     }
 
-    private boolean isOnKeyguard() {
-        return mBarState == KEYGUARD;
-    }
-
     /** Called when a HUN is dragged up or down to indicate the starting height for shade motion. */
     @VisibleForTesting
     void setHeadsUpDraggingStartingHeight(int startHeight) {
@@ -4434,7 +4457,7 @@
 
         @Override
         public void onHeadsUpPinned(NotificationEntry entry) {
-            if (!isOnKeyguard()) {
+            if (!isKeyguardShowing()) {
                 mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
                         entry.getHeadsUpAnimationView(), true);
             }
@@ -4447,7 +4470,7 @@
             // we need to make sure that an animation happens in this case, otherwise the
             // notification
             // will stick to the top without any interaction.
-            if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) {
+            if (isFullyCollapsed() && entry.isRowHeadsUp() && !isKeyguardShowing()) {
                 mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
                         entry.getHeadsUpAnimationView(), false);
                 entry.setHeadsUpIsVisible();
@@ -4748,7 +4771,7 @@
             // we need to ignore it on keyguard as this is a false alarm - transition from unlocked
             // to locked will trigger this event and we're not actually in the process of opening
             // the shade, lockscreen is just always expanded
-            if (mSplitShadeEnabled && !isOnKeyguard()) {
+            if (mSplitShadeEnabled && !isKeyguardShowing()) {
                 mQsController.setExpandImmediate(true);
             }
             mOpenCloseListener.onOpenStarted();
@@ -4799,8 +4822,11 @@
     private Consumer<Float> setTransitionY(
                 NotificationStackScrollLayoutController stackScroller) {
         return (Float translationY) -> {
-            mKeyguardStatusViewController.setTranslationY(translationY,  /* excludeMedia= */false);
-            stackScroller.setTranslationY(translationY);
+            if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+                mKeyguardStatusViewController.setTranslationY(translationY,
+                        /* excludeMedia= */false);
+                stackScroller.setTranslationY(translationY);
+            }
         };
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index ebb9935..5a8be1e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -37,11 +37,18 @@
     /** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */
     val qsExpansion: StateFlow<Float>
 
+    /** The amount the shade has expanded */
+    val shadeExpansion: StateFlow<Float>
+
     /** Amount shade has expanded with regard to the UDFPS location */
     val udfpsTransitionToFullShadeProgress: StateFlow<Float>
 
+    /** The amount QS has expanded without notifications */
     fun setQsExpansion(qsExpansion: Float)
     fun setUdfpsTransitionToFullShadeProgress(progress: Float)
+
+    /** The amount the shade has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded */
+    fun setShadeExpansion(expansion: Float)
 }
 
 /** Business logic for shade interactions */
@@ -69,7 +76,6 @@
 
                 val currentState = shadeExpansionStateManager.addExpansionListener(callback)
                 callback.onPanelExpansionChanged(currentState)
-                trySendWithFailureLogging(ShadeModel(), TAG, "initial shade expansion info")
 
                 awaitClose { shadeExpansionStateManager.removeExpansionListener(callback) }
             }
@@ -78,6 +84,9 @@
     private val _qsExpansion = MutableStateFlow(0f)
     override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
 
+    private val _shadeExpansion = MutableStateFlow(0f)
+    override val shadeExpansion: StateFlow<Float> = _shadeExpansion.asStateFlow()
+
     private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
     override val udfpsTransitionToFullShadeProgress: StateFlow<Float> =
         _udfpsTransitionToFullShadeProgress.asStateFlow()
@@ -85,6 +94,10 @@
         _qsExpansion.value = qsExpansion
     }
 
+    override fun setShadeExpansion(expansion: Float) {
+        _shadeExpansion.value = expansion
+    }
+
     override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
         _udfpsTransitionToFullShadeProgress.value = progress
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6fde84a..288d32e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -19,6 +19,8 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -43,6 +45,7 @@
     userSetupRepository: UserSetupRepository,
     deviceProvisionedController: DeviceProvisionedController,
     userInteractor: UserInteractor,
+    repository: ShadeRepository,
 ) {
     /** Emits true if the shade is currently allowed and false otherwise. */
     val isShadeEnabled: StateFlow<Boolean> =
@@ -50,6 +53,25 @@
             .map { it.isShadeEnabled() }
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
+    /** The amount [0-1] that the shade has been opened */
+    val shadeExpansion: Flow<Float> =
+        combine(repository.shadeExpansion, keyguardRepository.statusBarState) {
+            shadeExpansion,
+            statusBarState ->
+            // This is required, as shadeExpansion gets reset to 0f even with the shade open
+            if (statusBarState == StatusBarState.SHADE_LOCKED) {
+                1f
+            } else {
+                shadeExpansion
+            }
+        }
+
+    /**
+     * The amount [0-1] QS has been opened. Normal shade with notifications (QQS) visible will
+     * report 0f.
+     */
+    val qsExpansion: StateFlow<Float> = repository.qsExpansion
+
     /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
     val isExpandToQsEnabled: Flow<Boolean> =
         combine(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 672796a..25bb204 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -424,6 +424,7 @@
                 if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
                     fractionToShade =
                         MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
+                    shadeRepository.setShadeExpansion(fractionToShade)
                     nsslController.setTransitionToFullShadeAmount(fractionToShade)
 
                     qsTransitionController.dragDownAmount = value
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 874450b..4ed31c2 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
@@ -20,19 +20,27 @@
 import android.content.Context
 import com.android.systemui.R
 import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.dagger.SysUISingleton
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 
 /** Encapsulates business-logic specifically related to the shared notification stack container. */
+@SysUISingleton
 class SharedNotificationContainerInteractor
 @Inject
 constructor(
     configurationRepository: ConfigurationRepository,
     private val context: Context,
 ) {
+
+    private val _topPosition = MutableStateFlow(0f)
+    val topPosition = _topPosition.asStateFlow()
+
     val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
         configurationRepository.onAnyConfigurationChange
             .onStart { emit(Unit) }
@@ -54,6 +62,11 @@
             }
             .distinctUntilChanged()
 
+    /** Top position (without translation) of the shared container. */
+    fun setTopPosition(top: Float) {
+        _topPosition.value = top
+    }
+
     data class ConfigurationBasedDimensions(
         val useSplitShade: Boolean,
         val useLargeScreenHeader: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index fb1d55d..2af7181 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -19,6 +19,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
 import kotlinx.coroutines.launch
@@ -30,9 +31,10 @@
     fun bind(
         view: SharedNotificationContainer,
         viewModel: SharedNotificationContainerViewModel,
+        controller: NotificationStackScrollLayoutController,
     ) {
         view.repeatWhenAttached {
-            repeatOnLifecycle(Lifecycle.State.STARTED) {
+            repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
                     viewModel.configurationBasedDimensions.collect {
                         view.updateConstraints(
@@ -42,8 +44,29 @@
                             marginEnd = it.marginEnd,
                             marginBottom = it.marginBottom,
                         )
+
+                        controller.setOverExpansion(0f)
+                        controller.setOverScrollAmount(0)
+                        controller.updateFooter()
                     }
                 }
+
+                launch {
+                    viewModel.maxNotifications.collect {
+                        controller.setMaxDisplayedNotifications(it)
+                    }
+                }
+
+                launch {
+                    viewModel.position.collect {
+                        controller.updateTopPadding(
+                            it.top,
+                            controller.isAddOrRemoveAnimationPending()
+                        )
+                    }
+                }
+
+                launch { viewModel.translationY.collect { controller.setTranslationY(it) } }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index b2e5ac1..6f4adeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -17,18 +17,35 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
 
-/** View-model for the shared notification container */
+/** View-model for the shared notification container, used by both the shade and keyguard spaces */
 class SharedNotificationContainerViewModel
 @Inject
 constructor(
     interactor: SharedNotificationContainerInteractor,
+    keyguardInteractor: KeyguardInteractor,
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    notificationStackSizeCalculator: NotificationStackSizeCalculator,
+    controller: NotificationStackScrollLayoutController,
+    shadeInteractor: ShadeInteractor,
 ) {
+    private val statesForConstrainedNotifications =
+        setOf(KeyguardState.LOCKSCREEN, KeyguardState.AOD, KeyguardState.DOZING)
+
     val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
         interactor.configurationBasedDimensions
             .map {
@@ -43,6 +60,91 @@
             }
             .distinctUntilChanged()
 
+    /** If the user is visually on one of the unoccluded lockscreen states. */
+    val isOnLockscreen: Flow<Boolean> =
+        keyguardTransitionInteractor.finishedKeyguardState
+            .map { statesForConstrainedNotifications.contains(it) }
+            .distinctUntilChanged()
+
+    /** Are we purely on the keyguard without the shade/qs? */
+    val isOnLockscreenWithoutShade: Flow<Boolean> =
+        combine(
+                isOnLockscreen,
+                // Shade with notifications
+                shadeInteractor.shadeExpansion.map { it > 0f },
+                // Shade without notifications, quick settings only (pull down from very top on
+                // lockscreen)
+                shadeInteractor.qsExpansion.map { it > 0f },
+            ) { isKeyguard, isShadeVisible, qsExpansion ->
+                isKeyguard && !(isShadeVisible || qsExpansion)
+            }
+            .distinctUntilChanged()
+
+    /**
+     * The container occupies the entire screen, and must be positioned relative to other elements.
+     *
+     * On keyguard, this generally fits below the clock and above the lock icon, or in split shade,
+     * the top of the screen to the lock icon.
+     *
+     * When the shade is expanding, the position is controlled by... the shade.
+     */
+    val position: Flow<SharedNotificationContainerPosition> =
+        isOnLockscreenWithoutShade.flatMapLatest { onLockscreen ->
+            if (onLockscreen) {
+                combine(
+                    keyguardInteractor.sharedNotificationContainerPosition,
+                    configurationBasedDimensions
+                ) { position, config ->
+                    if (config.useSplitShade) {
+                        position.copy(top = 0f)
+                    } else {
+                        position
+                    }
+                }
+            } else {
+                interactor.topPosition.map { top ->
+                    keyguardInteractor.sharedNotificationContainerPosition.value.copy(top = top)
+                }
+            }
+        }
+
+    /**
+     * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
+     * translated as the keyguard fades out.
+     */
+    val translationY: Flow<Float> =
+        combine(isOnLockscreen, keyguardInteractor.keyguardTranslationY) {
+            isOnLockscreen,
+            translationY ->
+            if (isOnLockscreen) {
+                translationY
+            } else {
+                0f
+            }
+        }
+
+    /**
+     * When on keyguard, there is limited space to display notifications so calculate how many could
+     * be shown. Otherwise, there is no limit since the vertical space will be scrollable.
+     * TODO: b/296606746 - Need to rerun logic when notifs change
+     */
+    val maxNotifications: Flow<Int> =
+        combine(isOnLockscreen, shadeInteractor.shadeExpansion, position) {
+            onLockscreen,
+            shadeExpansion,
+            positionInfo ->
+            if (onLockscreen && shadeExpansion < 1f) {
+                notificationStackSizeCalculator.computeMaxKeyguardNotifications(
+                    controller.getView(),
+                    positionInfo.bottom - positionInfo.top,
+                    0f, // Vertical space for shelf is already accounted for
+                    controller.getShelfHeight().toFloat(),
+                )
+            } else {
+                -1 // No limit
+            }
+        }
+
     data class ConfigurationBasedDimensions(
         val marginStart: Int,
         val marginTop: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 6a3ebe6..4aa8b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2857,7 +2857,9 @@
                                     && mWakefulnessLifecycle.getLastWakeReason()
                                     == PowerManager.WAKE_REASON_POWER_BUTTON
                                     && mFingerprintManager.get().isPowerbuttonFps()
-                                    && mFingerprintManager.get().hasEnrolledFingerprints()
+                                    && mKeyguardUpdateMonitor
+                                    .getCachedIsUnlockWithFingerprintPossible(
+                                            mUserTracker.getUserId())
                                     && !touchToUnlockAnytime;
                     if (DEBUG_WAKEUP_DELAY) {
                         Log.d(TAG, "mShouldDelayWakeUpAnimation=" + mShouldDelayWakeUpAnimation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ComponentSystemUIDialog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ComponentSystemUIDialog.kt
new file mode 100644
index 0000000..38a6d39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ComponentSystemUIDialog.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.phone
+
+import android.annotation.CallSuper
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.OnBackPressedDispatcherOwner
+import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.savedstate.SavedStateRegistry
+import androidx.savedstate.SavedStateRegistryController
+import androidx.savedstate.SavedStateRegistryOwner
+import androidx.savedstate.setViewTreeSavedStateRegistryOwner
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.model.SysUiState
+
+/**
+ * A [SystemUIDialog] that implements [LifecycleOwner], [SavedStateRegistryOwner] and
+ * [OnBackPressedDispatcherOwner].
+ *
+ * This class was forked from [androidx.activity.ComponentDialog] and can be used to easily create
+ * SystemUI dialogs without the need to subclass [SystemUIDialog]. You should call
+ * [SystemUIDialogFactory.create] to easily instantiate this class.
+ *
+ * Important: [ComponentSystemUIDialog] should be created and shown on the main thread.
+ *
+ * @see SystemUIDialogFactory.create
+ */
+class ComponentSystemUIDialog(
+    context: Context,
+    theme: Int,
+    dismissOnDeviceLock: Boolean,
+    featureFlags: FeatureFlags,
+    dialogManager: SystemUIDialogManager,
+    sysUiState: SysUiState,
+    broadcastDispatcher: BroadcastDispatcher,
+    dialogLaunchAnimator: DialogLaunchAnimator,
+) :
+    SystemUIDialog(
+        context,
+        theme,
+        dismissOnDeviceLock,
+        featureFlags,
+        dialogManager,
+        sysUiState,
+        broadcastDispatcher,
+        dialogLaunchAnimator
+    ),
+    LifecycleOwner,
+    SavedStateRegistryOwner,
+    OnBackPressedDispatcherOwner {
+    private var _lifecycleRegistry: LifecycleRegistry? = null
+    private val lifecycleRegistry: LifecycleRegistry
+        get() = _lifecycleRegistry ?: LifecycleRegistry(this).also { _lifecycleRegistry = it }
+
+    private val savedStateRegistryController: SavedStateRegistryController =
+        SavedStateRegistryController.create(this)
+    override val savedStateRegistry: SavedStateRegistry
+        get() = savedStateRegistryController.savedStateRegistry
+
+    override val lifecycle: Lifecycle
+        get() = lifecycleRegistry
+
+    override fun onSaveInstanceState(): Bundle {
+        val bundle = super.onSaveInstanceState()
+        savedStateRegistryController.performSave(bundle)
+        return bundle
+    }
+
+    @CallSuper
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        onBackPressedDispatcher.setOnBackInvokedDispatcher(onBackInvokedDispatcher)
+        savedStateRegistryController.performRestore(savedInstanceState)
+        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
+    }
+
+    @CallSuper
+    override fun start() {
+        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
+    }
+
+    @CallSuper
+    override fun stop() {
+        // This is the closest thing to onDestroy that a Dialog has
+        // TODO(b/296180426): Make SystemUIDialog.onStop() and onStart() open again (annotated with
+        // @CallSuper) and do this *before* calling super.onStop(), like AndroidX ComponentDialog
+        // does.
+        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+        _lifecycleRegistry = null
+    }
+
+    @Suppress("DEPRECATION")
+    override val onBackPressedDispatcher = OnBackPressedDispatcher { super.onBackPressed() }
+
+    @CallSuper
+    override fun onBackPressed() {
+        onBackPressedDispatcher.onBackPressed()
+    }
+
+    override fun setContentView(layoutResID: Int) {
+        initializeViewTreeOwners()
+        super.setContentView(layoutResID)
+    }
+
+    override fun setContentView(view: View) {
+        initializeViewTreeOwners()
+        super.setContentView(view)
+    }
+
+    override fun setContentView(view: View, params: ViewGroup.LayoutParams?) {
+        initializeViewTreeOwners()
+        super.setContentView(view, params)
+    }
+
+    override fun addContentView(view: View, params: ViewGroup.LayoutParams?) {
+        initializeViewTreeOwners()
+        super.addContentView(view, params)
+    }
+
+    /**
+     * Sets the view tree owners before setting the content view so that the inflation process and
+     * attach listeners will see them already present.
+     */
+    @CallSuper
+    open fun initializeViewTreeOwners() {
+        window!!.decorView.setViewTreeLifecycleOwner(this)
+        window!!.decorView.setViewTreeOnBackPressedDispatcherOwner(this)
+        window!!.decorView.setViewTreeSavedStateRegistryOwner(this)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index baf94fc..69510ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -68,7 +68,7 @@
     // TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on.
     private static final String FLAG_TABLET_DIALOG_WIDTH =
             "persist.systemui.flag_tablet_dialog_width";
-    private static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;
+    public static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;
 
     private final Context mContext;
     private final FeatureFlags mFeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
new file mode 100644
index 0000000..3b15065
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogFactory.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.phone
+
+import android.content.Context
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.model.SysUiState
+import com.android.systemui.util.Assert
+import javax.inject.Inject
+
+/** A factory to easily instantiate a [ComponentSystemUIDialog]. */
+class SystemUIDialogFactory
+@Inject
+constructor(
+    @Application val applicationContext: Context,
+    private val featureFlags: FeatureFlagsClassic,
+    private val dialogManager: SystemUIDialogManager,
+    private val sysUiState: SysUiState,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val dialogLaunchAnimator: DialogLaunchAnimator,
+) {
+    /**
+     * Create a new [ComponentSystemUIDialog].
+     *
+     * Important: This should be called on the main thread and the returned dialog should be shown
+     * on the main thread.
+     *
+     * @param context the [Context] in which the dialog will be constructed.
+     * @param dismissOnDeviceLock whether the dialog should be automatically dismissed when the
+     *   device is locked (true by default).
+     */
+    fun create(
+        context: Context = this.applicationContext,
+        dismissOnDeviceLock: Boolean = SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
+    ): ComponentSystemUIDialog {
+        Assert.isMainThread()
+
+        return ComponentSystemUIDialog(
+            context,
+            SystemUIDialog.DEFAULT_THEME,
+            dismissOnDeviceLock,
+            featureFlags,
+            dialogManager,
+            sysUiState,
+            broadcastDispatcher,
+            dialogLaunchAnimator,
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index b67f280..c91313ad 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -22,13 +22,11 @@
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.plugins.ClockAnimations
@@ -38,7 +36,6 @@
 import com.android.systemui.plugins.ClockFaceController
 import com.android.systemui.plugins.ClockFaceEvents
 import com.android.systemui.plugins.ClockTickRate
-import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -47,6 +44,8 @@
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
+import java.util.TimeZone
+import java.util.concurrent.Executor
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.TestScope
@@ -63,10 +62,8 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import java.util.TimeZone
-import java.util.concurrent.Executor
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -82,7 +79,6 @@
     @Mock private lateinit var clock: ClockController
     @Mock private lateinit var mainExecutor: DelayableExecutor
     @Mock private lateinit var bgExecutor: Executor
-    @Mock private lateinit var featureFlags: FeatureFlags
     @Mock private lateinit var smallClockController: ClockFaceController
     @Mock private lateinit var smallClockView: View
     @Mock private lateinit var smallClockViewTreeObserver: ViewTreeObserver
@@ -95,9 +91,7 @@
     @Mock private lateinit var largeClockEvents: ClockFaceEvents
     @Mock private lateinit var parentView: View
     @Mock private lateinit var transitionRepository: KeyguardTransitionRepository
-    @Mock private lateinit var commandQueue: CommandQueue
     private lateinit var repository: FakeKeyguardRepository
-    private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
     @Mock private lateinit var smallLogBuffer: LogBuffer
     @Mock private lateinit var largeLogBuffer: LogBuffer
     private lateinit var underTest: ClockEventController
@@ -123,31 +117,35 @@
             .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE))
 
         repository = FakeKeyguardRepository()
-        bouncerRepository = FakeKeyguardBouncerRepository()
 
-        underTest = ClockEventController(
-            KeyguardInteractor(
+        val withDeps =
+            KeyguardInteractorFactory.create(
                 repository = repository,
-                commandQueue = commandQueue,
-                featureFlags = featureFlags,
-                bouncerRepository = bouncerRepository,
-                configurationRepository = FakeConfigurationRepository(),
-            ),
-            KeyguardTransitionInteractorFactory.create(
-                    scope = TestScope().backgroundScope,
-            ).keyguardTransitionInteractor,
-            broadcastDispatcher,
-            batteryController,
-            keyguardUpdateMonitor,
-            configurationController,
-            context.resources,
-            context,
-            mainExecutor,
-            bgExecutor,
-            smallLogBuffer,
-            largeLogBuffer,
-            featureFlags
-        )
+            )
+
+        withDeps.featureFlags.apply {
+            set(Flags.REGION_SAMPLING, false)
+            set(Flags.DOZING_MIGRATION_1, false)
+        }
+        underTest =
+            ClockEventController(
+                withDeps.keyguardInteractor,
+                KeyguardTransitionInteractorFactory.create(
+                        scope = TestScope().backgroundScope,
+                    )
+                    .keyguardTransitionInteractor,
+                broadcastDispatcher,
+                batteryController,
+                keyguardUpdateMonitor,
+                configurationController,
+                context.resources,
+                context,
+                mainExecutor,
+                bgExecutor,
+                smallLogBuffer,
+                largeLogBuffer,
+                withDeps.featureFlags
+            )
         underTest.clock = clock
 
         runBlocking(IMMEDIATE) {
@@ -171,38 +169,41 @@
     }
 
     @Test
-    fun themeChanged_verifyClockPaletteUpdated() = runBlocking(IMMEDIATE) {
-         verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
-         verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
+    fun themeChanged_verifyClockPaletteUpdated() =
+        runBlocking(IMMEDIATE) {
+            verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
+            verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
 
-        val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
-        verify(configurationController).addCallback(capture(captor))
-        captor.value.onThemeChanged()
+            val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
+            verify(configurationController).addCallback(capture(captor))
+            captor.value.onThemeChanged()
 
-        verify(events).onColorPaletteChanged(any())
-    }
+            verify(events).onColorPaletteChanged(any())
+        }
 
     @Test
-    fun fontChanged_verifyFontSizeUpdated() = runBlocking(IMMEDIATE) {
-        val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
-        verify(configurationController).addCallback(capture(captor))
-        captor.value.onDensityOrFontScaleChanged()
+    fun fontChanged_verifyFontSizeUpdated() =
+        runBlocking(IMMEDIATE) {
+            val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
+            verify(configurationController).addCallback(capture(captor))
+            captor.value.onDensityOrFontScaleChanged()
 
-        verify(smallClockEvents, times(2)).onFontSettingChanged(anyFloat())
-        verify(largeClockEvents, times(2)).onFontSettingChanged(anyFloat())
-    }
+            verify(smallClockEvents, times(2)).onFontSettingChanged(anyFloat())
+            verify(largeClockEvents, times(2)).onFontSettingChanged(anyFloat())
+        }
 
     @Test
-    fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) {
-        val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
-        verify(batteryController).addCallback(capture(batteryCaptor))
-        val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
-        verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
-        keyguardCaptor.value.onKeyguardVisibilityChanged(true)
-        batteryCaptor.value.onBatteryLevelChanged(10, false, true)
+    fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() =
+        runBlocking(IMMEDIATE) {
+            val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
+            verify(batteryController).addCallback(capture(batteryCaptor))
+            val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
+            keyguardCaptor.value.onKeyguardVisibilityChanged(true)
+            batteryCaptor.value.onBatteryLevelChanged(10, false, true)
 
-        verify(animations, times(2)).charge()
-    }
+            verify(animations, times(2)).charge()
+        }
 
     @Test
     fun batteryCallback_keyguardShowingCharging_Duplicate_verifyChargeAnimation() =
@@ -219,16 +220,17 @@
         }
 
     @Test
-    fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() = runBlocking(IMMEDIATE) {
-        val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
-        verify(batteryController).addCallback(capture(batteryCaptor))
-        val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
-        verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
-        keyguardCaptor.value.onKeyguardVisibilityChanged(false)
-        batteryCaptor.value.onBatteryLevelChanged(10, false, true)
+    fun batteryCallback_keyguardHiddenCharging_verifyChargeAnimation() =
+        runBlocking(IMMEDIATE) {
+            val batteryCaptor = argumentCaptor<BatteryController.BatteryStateChangeCallback>()
+            verify(batteryController).addCallback(capture(batteryCaptor))
+            val keyguardCaptor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCaptor))
+            keyguardCaptor.value.onKeyguardVisibilityChanged(false)
+            batteryCaptor.value.onBatteryLevelChanged(10, false, true)
 
-        verify(animations, never()).charge()
-    }
+            verify(animations, never()).charge()
+        }
 
     @Test
     fun batteryCallback_keyguardShowingNotCharging_verifyChargeAnimation() =
@@ -244,102 +246,111 @@
         }
 
     @Test
-    fun localeCallback_verifyClockNotified() = runBlocking(IMMEDIATE) {
-        val captor = argumentCaptor<BroadcastReceiver>()
-        verify(broadcastDispatcher).registerReceiver(
-            capture(captor), any(), eq(null), eq(null), anyInt(), eq(null)
-        )
-        captor.value.onReceive(context, mock())
+    fun localeCallback_verifyClockNotified() =
+        runBlocking(IMMEDIATE) {
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(broadcastDispatcher)
+                .registerReceiver(capture(captor), any(), eq(null), eq(null), anyInt(), eq(null))
+            captor.value.onReceive(context, mock())
 
-        verify(events).onLocaleChanged(any())
-    }
+            verify(events).onLocaleChanged(any())
+        }
 
     @Test
-    fun keyguardCallback_visibilityChanged_clockDozeCalled() = runBlocking(IMMEDIATE) {
-        val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
-        verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+    fun keyguardCallback_visibilityChanged_clockDozeCalled() =
+        runBlocking(IMMEDIATE) {
+            val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(capture(captor))
 
-        captor.value.onKeyguardVisibilityChanged(true)
-        verify(animations, never()).doze(0f)
+            captor.value.onKeyguardVisibilityChanged(true)
+            verify(animations, never()).doze(0f)
 
-        captor.value.onKeyguardVisibilityChanged(false)
-        verify(animations, times(2)).doze(0f)
-    }
+            captor.value.onKeyguardVisibilityChanged(false)
+            verify(animations, times(2)).doze(0f)
+        }
 
     @Test
-    fun keyguardCallback_timeFormat_clockNotified() = runBlocking(IMMEDIATE) {
-        val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
-        verify(keyguardUpdateMonitor).registerCallback(capture(captor))
-        captor.value.onTimeFormatChanged("12h")
+    fun keyguardCallback_timeFormat_clockNotified() =
+        runBlocking(IMMEDIATE) {
+            val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+            captor.value.onTimeFormatChanged("12h")
 
-        verify(events).onTimeFormatChanged(false)
-    }
+            verify(events).onTimeFormatChanged(false)
+        }
 
     @Test
-    fun keyguardCallback_timezoneChanged_clockNotified() = runBlocking(IMMEDIATE) {
-        val mockTimeZone = mock<TimeZone>()
-        val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
-        verify(keyguardUpdateMonitor).registerCallback(capture(captor))
-        captor.value.onTimeZoneChanged(mockTimeZone)
+    fun keyguardCallback_timezoneChanged_clockNotified() =
+        runBlocking(IMMEDIATE) {
+            val mockTimeZone = mock<TimeZone>()
+            val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+            captor.value.onTimeZoneChanged(mockTimeZone)
 
-        verify(events).onTimeZoneChanged(mockTimeZone)
-    }
+            verify(events).onTimeZoneChanged(mockTimeZone)
+        }
 
     @Test
-    fun keyguardCallback_userSwitched_clockNotified() = runBlocking(IMMEDIATE) {
-        val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
-        verify(keyguardUpdateMonitor).registerCallback(capture(captor))
-        captor.value.onUserSwitchComplete(10)
+    fun keyguardCallback_userSwitched_clockNotified() =
+        runBlocking(IMMEDIATE) {
+            val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(capture(captor))
+            captor.value.onUserSwitchComplete(10)
 
-        verify(events).onTimeFormatChanged(false)
-    }
+            verify(events).onTimeFormatChanged(false)
+        }
 
     @Test
-    fun keyguardCallback_verifyKeyguardChanged() = runBlocking(IMMEDIATE) {
-        val job = underTest.listenForDozeAmount(this)
-        repository.setDozeAmount(0.4f)
+    fun keyguardCallback_verifyKeyguardChanged() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozeAmount(this)
+            repository.setDozeAmount(0.4f)
 
-        yield()
+            yield()
 
-        verify(animations, times(2)).doze(0.4f)
+            verify(animations, times(2)).doze(0.4f)
 
-        job.cancel()
-    }
+            job.cancel()
+        }
 
     @Test
-    fun unregisterListeners_validate() = runBlocking(IMMEDIATE) {
-        underTest.unregisterListeners()
-        verify(broadcastDispatcher).unregisterReceiver(any())
-        verify(configurationController).removeCallback(any())
-        verify(batteryController).removeCallback(any())
-        verify(keyguardUpdateMonitor).removeCallback(any())
-        verify(smallClockController.view)
+    fun unregisterListeners_validate() =
+        runBlocking(IMMEDIATE) {
+            underTest.unregisterListeners()
+            verify(broadcastDispatcher).unregisterReceiver(any())
+            verify(configurationController).removeCallback(any())
+            verify(batteryController).removeCallback(any())
+            verify(keyguardUpdateMonitor).removeCallback(any())
+            verify(smallClockController.view)
                 .removeOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
-        verify(largeClockController.view)
+            verify(largeClockController.view)
                 .removeOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
-    }
+        }
 
     @Test
-    fun registerOnAttachStateChangeListener_validate() = runBlocking(IMMEDIATE) {
-        verify(smallClockController.view)
-            .addOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
-        verify(largeClockController.view)
-            .addOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
-    }
+    fun registerOnAttachStateChangeListener_validate() =
+        runBlocking(IMMEDIATE) {
+            verify(smallClockController.view)
+                .addOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
+            verify(largeClockController.view)
+                .addOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
+        }
 
     @Test
-    fun registerAndRemoveOnGlobalLayoutListener_correctly() = runBlocking(IMMEDIATE) {
-        underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
-        verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
-        underTest.smallClockOnAttachStateChangeListener!!.onViewDetachedFromWindow(smallClockView)
-        verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
-    }
+    fun registerAndRemoveOnGlobalLayoutListener_correctly() =
+        runBlocking(IMMEDIATE) {
+            underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
+            verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
+            underTest.smallClockOnAttachStateChangeListener!!.onViewDetachedFromWindow(
+                smallClockView
+            )
+            verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
+        }
 
     @Test
     fun registerOnGlobalLayoutListener_RemoveOnAttachStateChangeListener_correctly() =
         runBlocking(IMMEDIATE) {
-            underTest.smallClockOnAttachStateChangeListener!!
-                .onViewAttachedToWindow(smallClockView)
+            underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
             verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
             underTest.unregisterListeners()
             verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index b18137c..b9e3f14 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -47,7 +47,6 @@
 import com.android.systemui.doze.util.BurnInHelperKt;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory;
 import com.android.systemui.plugins.FalsingManager;
@@ -92,7 +91,6 @@
     protected @Mock ConfigurationController mConfigurationController;
     protected @Mock VibratorHelper mVibrator;
     protected @Mock AuthRippleController mAuthRippleController;
-    protected @Mock KeyguardTransitionRepository mTransitionRepository;
     protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
     protected FakeFeatureFlags mFeatureFlags;
     protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@@ -165,8 +163,8 @@
                 mAuthRippleController,
                 mResources,
                 KeyguardTransitionInteractorFactory.create(
-                        TestScopeProvider.getTestScope().getBackgroundScope(),
-                                mTransitionRepository).getKeyguardTransitionInteractor(),
+                        TestScopeProvider.getTestScope().getBackgroundScope())
+                                .getKeyguardTransitionInteractor(),
                 KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
                 mFeatureFlags,
                 mPrimaryBouncerInteractor
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 e73d580..36822e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -34,8 +34,6 @@
 import com.android.systemui.SystemUIAppComponentFactoryBase
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogLaunchAnimator
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.dock.DockManagerFake
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
@@ -45,9 +43,8 @@
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
 import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer
@@ -58,7 +55,6 @@
 import com.android.systemui.settings.UserTracker
 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.CommandQueue
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.mockito.any
@@ -95,7 +91,6 @@
     @Mock private lateinit var backgroundHandler: Handler
     @Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
     @Mock private lateinit var launchAnimator: DialogLaunchAnimator
-    @Mock private lateinit var commandQueue: CommandQueue
     @Mock private lateinit var devicePolicyManager: DevicePolicyManager
     @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
 
@@ -183,13 +178,10 @@
         underTest.interactor =
             KeyguardQuickAffordanceInteractor(
                 keyguardInteractor =
-                    KeyguardInteractor(
-                        repository = FakeKeyguardRepository(),
-                        commandQueue = commandQueue,
-                        featureFlags = featureFlags,
-                        bouncerRepository = FakeKeyguardBouncerRepository(),
-                        configurationRepository = FakeConfigurationRepository(),
-                    ),
+                    KeyguardInteractorFactory.create(
+                            featureFlags = featureFlags,
+                        )
+                        .keyguardInteractor,
                 lockPatternUtils = lockPatternUtils,
                 keyguardStateController = keyguardStateController,
                 userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 4b09468..972af4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
+import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.onCompletion
 import kotlinx.coroutines.test.TestScope
@@ -52,6 +53,7 @@
     private lateinit var repository: FakeKeyguardRepository
     private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
     private lateinit var configurationRepository: FakeConfigurationRepository
+    private lateinit var shadeRepository: FakeShadeRepository
 
     @Before
     fun setUp() {
@@ -62,6 +64,7 @@
         repository = FakeKeyguardRepository()
         bouncerRepository = FakeKeyguardBouncerRepository()
         configurationRepository = FakeConfigurationRepository()
+        shadeRepository = FakeShadeRepository()
         underTest =
             KeyguardInteractor(
                 repository,
@@ -69,6 +72,7 @@
                 featureFlags,
                 bouncerRepository,
                 configurationRepository,
+                shadeRepository,
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
index 1dcb55d..f24ea6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
@@ -116,13 +116,13 @@
                     keyguardUpdateMonitor,
                 ),
                 fingerprintAuthRepository,
-                KeyguardInteractor(
-                    keyguardRepository,
-                    commandQueue = mock(),
-                    featureFlags,
-                    bouncerRepository,
-                    configurationRepository,
-                ),
+                KeyguardInteractorFactory.create(
+                        featureFlags = featureFlags,
+                        repository = keyguardRepository,
+                        bouncerRepository = bouncerRepository,
+                        configurationRepository = configurationRepository,
+                    )
+                    .keyguardInteractor,
                 PrimaryBouncerInteractor(
                     bouncerRepository,
                     primaryBouncerView = mock(),
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 981e44b..209dcc1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -145,6 +145,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DozeParameters;
@@ -322,6 +323,7 @@
     @Mock private JavaAdapter mJavaAdapter;
     @Mock private CastController mCastController;
     @Mock private KeyguardRootView mKeyguardRootView;
+    @Mock private SharedNotificationContainerInteractor mSharedNotificationContainerInteractor;
 
     protected final int mMaxUdfpsBurnInOffsetY = 5;
     protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -650,6 +652,7 @@
                 mKeyuardLongPressViewModel,
                 mKeyguardInteractor,
                 mActivityStarter,
+                mSharedNotificationContainerInteractor,
                 mKeyguardViewConfigurator,
                 mKeyguardFaceAuthInteractor,
                 mKeyguardRootView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index a2c2912..e22e571 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -49,7 +49,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
-import com.android.systemui.shade.data.repository.ShadeRepository;
+import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -147,6 +147,7 @@
     protected FakeDisableFlagsRepository mDisableFlagsRepository =
             new FakeDisableFlagsRepository();
     protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
+    protected FakeShadeRepository mShadeRepository = new FakeShadeRepository();
 
     protected SysuiStatusBarStateController mStatusBarStateController;
     protected ShadeInteractor mShadeInteractor;
@@ -174,7 +175,8 @@
                         mKeyguardRepository,
                         new FakeUserSetupRepository(),
                         mDeviceProvisionedController,
-                        mUserInteractor
+                        mUserInteractor,
+                        mShadeRepository
                 );
 
         KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
@@ -249,7 +251,7 @@
                 mShadeLogger,
                 mDumpManager,
                 mock(KeyguardFaceAuthInteractor.class),
-                mock(ShadeRepository.class),
+                mShadeRepository,
                 mShadeInteractor,
                 new JavaAdapter(mTestScope.getBackgroundScope()),
                 mCastController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index cdcd1a2..e6e7482 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
+import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
@@ -69,6 +70,7 @@
     private val userRepository = FakeUserRepository()
     private val disableFlagsRepository = FakeDisableFlagsRepository()
     private val keyguardRepository = FakeKeyguardRepository()
+    private val shadeRepository = FakeShadeRepository()
 
     @Mock private lateinit var manager: UserManager
     @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@@ -143,6 +145,7 @@
                 userSetupRepository,
                 deviceProvisionedController,
                 userInteractor,
+                shadeRepository,
             )
     }
 
@@ -353,4 +356,29 @@
             // THEN expand is enabled
             assertThat(actual).isTrue()
         }
+
+    @Test
+    fun fullShadeExpansionWhenShadeLocked() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+            shadeRepository.setShadeExpansion(0.5f)
+
+            assertThat(actual).isEqualTo(1f)
+        }
+
+    @Test
+    fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+
+            shadeRepository.setShadeExpansion(0.5f)
+            assertThat(actual).isEqualTo(0.5f)
+
+            shadeRepository.setShadeExpansion(0.8f)
+            assertThat(actual).isEqualTo(0.8f)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index e26a8bd..fdaea22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -58,9 +58,8 @@
         MockitoAnnotations.initMocks(this)
 
         underTest = ShadeRepositoryImpl(shadeExpansionStateManager)
-        `when`(shadeExpansionStateManager.addExpansionListener(any())).thenReturn(
-            ShadeExpansionChangeEvent(0f, false, false, 0f)
-        )
+        `when`(shadeExpansionStateManager.addExpansionListener(any()))
+            .thenReturn(ShadeExpansionChangeEvent(0f, false, false, 0f))
     }
 
     @Test
@@ -122,6 +121,21 @@
         }
 
     @Test
+    fun updateShadeExpansion() =
+        testScope.runTest {
+            assertThat(underTest.shadeExpansion.value).isEqualTo(0f)
+
+            underTest.setShadeExpansion(.5f)
+            assertThat(underTest.shadeExpansion.value).isEqualTo(.5f)
+
+            underTest.setShadeExpansion(.82f)
+            assertThat(underTest.shadeExpansion.value).isEqualTo(.82f)
+
+            underTest.setShadeExpansion(1f)
+            assertThat(underTest.shadeExpansion.value).isEqualTo(1f)
+        }
+
+    @Test
     fun updateUdfpsTransitionToFullShadeProgress() =
         testScope.runTest {
             assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(0f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 4a2518a..51e72c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -60,8 +60,8 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 private fun <T> anyObject(): T {
     return Mockito.anyObject<T>()
@@ -102,21 +102,24 @@
     @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
     private val disableFlagsRepository = FakeDisableFlagsRepository()
     private val keyguardRepository = FakeKeyguardRepository()
-    private val shadeInteractor = ShadeInteractor(
-        testScope.backgroundScope,
-        disableFlagsRepository,
-        keyguardRepository,
-        userSetupRepository = FakeUserSetupRepository(),
-        deviceProvisionedController = mock(),
-        userInteractor = mock(),
-    )
-    private val powerInteractor = PowerInteractor(
-        FakePowerRepository(),
-        keyguardRepository,
-        FalsingCollectorFake(),
-        screenOffAnimationController = mock(),
-        statusBarStateController = mock(),
-    )
+    private val shadeInteractor =
+        ShadeInteractor(
+            testScope.backgroundScope,
+            disableFlagsRepository,
+            keyguardRepository,
+            userSetupRepository = FakeUserSetupRepository(),
+            deviceProvisionedController = mock(),
+            userInteractor = mock(),
+            repository = FakeShadeRepository(),
+        )
+    private val powerInteractor =
+        PowerInteractor(
+            FakePowerRepository(),
+            keyguardRepository,
+            FalsingCollectorFake(),
+            screenOffAnimationController = mock(),
+            statusBarStateController = mock(),
+        )
     @JvmField @Rule val mockito = MockitoJUnit.rule()
 
     private val configurationController = FakeConfigurationController()
@@ -127,14 +130,13 @@
         disableFlagsRepository.disableFlags.value = DisableFlagsModel()
         testScope.runCurrent()
 
-        val helper = NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this))
+        val helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
         row = helper.createRow()
-        context.getOrCreateTestableResources()
-                .addOverride(R.bool.config_use_split_notification_shade, false)
-        context.getOrCreateTestableResources()
+        context
+            .getOrCreateTestableResources()
+            .addOverride(R.bool.config_use_split_notification_shade, false)
+        context
+            .getOrCreateTestableResources()
             .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
         transitionController =
             LockscreenShadeTransitionController(
@@ -154,15 +156,20 @@
                 splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
                 singleShadeOverScrollerFactory = { singleShadeOverScroller },
                 scrimTransitionController =
-                LockscreenShadeScrimTransitionController(
-                    scrimController, context, configurationController, dumpManager),
+                    LockscreenShadeScrimTransitionController(
+                        scrimController,
+                        context,
+                        configurationController,
+                        dumpManager
+                    ),
                 keyguardTransitionControllerFactory = { notificationPanelController ->
                     LockscreenShadeKeyguardTransitionController(
                         mediaHierarchyManager,
                         notificationPanelController,
                         context,
                         configurationController,
-                        dumpManager)
+                        dumpManager
+                    )
                 },
                 qsTransitionControllerFactory = { qsTransitionController },
                 activityStarter = activityStarter,
@@ -180,8 +187,8 @@
         whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         whenever(nsslController.isInLockedDownShade).thenReturn(false)
         whenever(qS.isFullyCollapsed).thenReturn(true)
-        whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn(
-                true)
+        whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt()))
+            .thenReturn(true)
         whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
         whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
         whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
@@ -228,8 +235,10 @@
         whenever(statusbarStateController.isDozing).thenReturn(false)
         transitionController.goToLockedShade(null)
         verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
-        assertFalse("Waking to shade locked when not dozing",
-                transitionController.isWakingToShadeLocked)
+        assertFalse(
+            "Waking to shade locked when not dozing",
+            transitionController.isWakingToShadeLocked
+        )
     }
 
     @Test
@@ -243,9 +252,10 @@
 
     @Test
     fun testDontGoWhenShadeDisabled() {
-        disableFlagsRepository.disableFlags.value = DisableFlagsModel(
-            disable2 = DISABLE2_NOTIFICATION_SHADE,
-        )
+        disableFlagsRepository.disableFlags.value =
+            DisableFlagsModel(
+                disable2 = DISABLE2_NOTIFICATION_SHADE,
+            )
         testScope.runCurrent()
         transitionController.goToLockedShade(null)
         verify(statusbarStateController, never()).setState(anyInt())
@@ -298,8 +308,8 @@
         verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat())
         verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
         verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
-        verify(transitionControllerCallback, never()).setTransitionToFullShadeAmount(anyFloat(),
-                anyBoolean(), anyLong())
+        verify(transitionControllerCallback, never())
+            .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
         verify(qsTransitionController, never()).dragDownAmount = anyFloat()
     }
 
@@ -309,15 +319,16 @@
         verify(nsslController).setTransitionToFullShadeAmount(anyFloat())
         verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
         verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
-        verify(transitionControllerCallback).setTransitionToFullShadeAmount(anyFloat(),
-                anyBoolean(), anyLong())
+        verify(transitionControllerCallback)
+            .setTransitionToFullShadeAmount(anyFloat(), anyBoolean(), anyLong())
         verify(qsTransitionController).dragDownAmount = 10f
         verify(depthController).transitionToFullShadeProgress = anyFloat()
     }
 
     @Test
     fun testDragDownAmount_depthDistanceIsZero_setsProgressToZero() {
-        context.getOrCreateTestableResources()
+        context
+            .getOrCreateTestableResources()
             .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 0)
         configurationController.notifyConfigurationChanged()
 
@@ -328,7 +339,8 @@
 
     @Test
     fun testDragDownAmount_depthDistanceNonZero_setsProgressBasedOnDistance() {
-        context.getOrCreateTestableResources()
+        context
+            .getOrCreateTestableResources()
             .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
         configurationController.notifyConfigurationChanged()
 
@@ -346,13 +358,14 @@
 
     @Test
     fun setDragAmount_setsKeyguardAlphaBasedOnDistance() {
-        val alphaDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+        val alphaDistance =
+            context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance
+            )
         transitionController.dragDownAmount = 10f
 
         val expectedAlpha = 1 - 10f / alphaDistance
-        verify(shadeViewController)
-                .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
+        verify(shadeViewController).setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
     }
 
     @Test
@@ -378,8 +391,7 @@
 
         transitionController.dragDownAmount = 10f
 
-        verify(shadeViewController)
-            .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
+        verify(shadeViewController).setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
     }
 
     @Test
@@ -392,10 +404,12 @@
 
         val distance =
             context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_keyguard_transition_distance)
+                R.dimen.lockscreen_shade_keyguard_transition_distance
+            )
         val offset =
             context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_keyguard_transition_vertical_offset)
+                R.dimen.lockscreen_shade_keyguard_transition_vertical_offset
+            )
         val expectedTranslation = 10f / distance * offset
         verify(shadeViewController)
             .setKeyguardTransitionProgress(anyFloat(), eq(expectedTranslation.toInt()))
@@ -411,16 +425,19 @@
     @Test
     fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
         val distance = 10
-        context.orCreateTestableResources
-                .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+        context.orCreateTestableResources.addOverride(
+            R.dimen.lockscreen_shade_scrim_transition_distance,
+            distance
+        )
         configurationController.notifyConfigurationChanged()
 
         transitionController.dragDownAmount = 5f
 
-        verify(scrimController).transitionToFullShadeProgress(
+        verify(scrimController)
+            .transitionToFullShadeProgress(
                 progress = eq(0.5f),
                 lockScreenNotificationsProgress = anyFloat()
-        )
+            )
     }
 
     @Test
@@ -428,17 +445,22 @@
         val distance = 100
         val delay = 10
         context.orCreateTestableResources.addOverride(
-                R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+            R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
+            distance
+        )
         context.orCreateTestableResources.addOverride(
-                R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+            R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
+            delay
+        )
         configurationController.notifyConfigurationChanged()
 
         transitionController.dragDownAmount = 20f
 
-        verify(scrimController).transitionToFullShadeProgress(
+        verify(scrimController)
+            .transitionToFullShadeProgress(
                 progress = anyFloat(),
                 lockScreenNotificationsProgress = eq(0.1f)
-        )
+            )
     }
 
     @Test
@@ -446,17 +468,22 @@
         val distance = 100
         val delay = 50
         context.orCreateTestableResources.addOverride(
-                R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+            R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
+            distance
+        )
         context.orCreateTestableResources.addOverride(
-                R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+            R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
+            delay
+        )
         configurationController.notifyConfigurationChanged()
 
         transitionController.dragDownAmount = 20f
 
-        verify(scrimController).transitionToFullShadeProgress(
+        verify(scrimController)
+            .transitionToFullShadeProgress(
                 progress = anyFloat(),
                 lockScreenNotificationsProgress = eq(0f)
-        )
+            )
     }
 
     @Test
@@ -464,17 +491,22 @@
         val distance = 100
         val delay = 50
         context.orCreateTestableResources.addOverride(
-                R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+            R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
+            distance
+        )
         context.orCreateTestableResources.addOverride(
-                R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+            R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
+            delay
+        )
         configurationController.notifyConfigurationChanged()
 
         transitionController.dragDownAmount = 999999f
 
-        verify(scrimController).transitionToFullShadeProgress(
+        verify(scrimController)
+            .transitionToFullShadeProgress(
                 progress = anyFloat(),
                 lockScreenNotificationsProgress = eq(1f)
-        )
+            )
     }
 
     @Test
@@ -508,8 +540,10 @@
 
     @Test
     fun setDragDownAmount_inSplitShade_setsKeyguardStatusBarAlphaBasedOnDistance() {
-        val alphaDistance = context.resources.getDimensionPixelSize(
-            R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+        val alphaDistance =
+            context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance
+            )
         val dragDownAmount = 10f
         enableSplitShade()
 
@@ -549,9 +583,6 @@
         progress: Float,
         lockScreenNotificationsProgress: Float
     ) {
-        scrimController.setTransitionToFullShadeProgress(
-                progress,
-                lockScreenNotificationsProgress
-        )
+        scrimController.setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
     }
 }
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 afd9954..55b52dc 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,122 +21,369 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
+    private val testScope = TestScope(StandardTestDispatcher())
+
+    private val disableFlagsRepository = FakeDisableFlagsRepository()
+    private val userSetupRepository = FakeUserSetupRepository()
+    private val shadeRepository = FakeShadeRepository()
+    private val keyguardRepository = FakeKeyguardRepository()
+
     private lateinit var configurationRepository: FakeConfigurationRepository
     private lateinit var sharedNotificationContainerInteractor:
         SharedNotificationContainerInteractor
     private lateinit var underTest: SharedNotificationContainerViewModel
+    private lateinit var keyguardInteractor: KeyguardInteractor
+    private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var shadeInteractor: ShadeInteractor
+
+    @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator
+    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock private lateinit var userInteractor: UserInteractor
+    @Mock
+    private lateinit var notificationStackScrollLayoutController:
+        NotificationStackScrollLayoutController
 
     @Before
     fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())
+        whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0)
+
         configurationRepository = FakeConfigurationRepository()
+        KeyguardTransitionInteractorFactory.create(
+                scope = testScope.backgroundScope,
+            )
+            .also {
+                keyguardInteractor = it.keyguardInteractor
+                keyguardTransitionInteractor = it.keyguardTransitionInteractor
+                keyguardTransitionRepository = it.repository
+            }
+
+        shadeInteractor =
+            ShadeInteractor(
+                testScope.backgroundScope,
+                disableFlagsRepository,
+                keyguardRepository,
+                userSetupRepository,
+                deviceProvisionedController,
+                userInteractor,
+                shadeRepository,
+            )
+
         sharedNotificationContainerInteractor =
             SharedNotificationContainerInteractor(
                 configurationRepository,
                 mContext,
             )
-        underTest = SharedNotificationContainerViewModel(sharedNotificationContainerInteractor)
+        underTest =
+            SharedNotificationContainerViewModel(
+                sharedNotificationContainerInteractor,
+                keyguardInteractor,
+                keyguardTransitionInteractor,
+                notificationStackSizeCalculator,
+                notificationStackScrollLayoutController,
+                shadeInteractor
+            )
     }
 
     @Test
-    fun validateMarginStartInSplitShade() = runTest {
-        overrideResource(R.bool.config_use_split_notification_shade, true)
-        overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
+    fun validateMarginStartInSplitShade() =
+        testScope.runTest {
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
-        val dimens = collectLastValue(underTest.configurationBasedDimensions)
+            val dimens by collectLastValue(underTest.configurationBasedDimensions)
 
-        configurationRepository.onAnyConfigurationChange()
-        runCurrent()
+            configurationRepository.onAnyConfigurationChange()
 
-        val lastDimens = dimens()!!
-
-        assertThat(lastDimens.marginStart).isEqualTo(0)
-    }
+            assertThat(dimens!!.marginStart).isEqualTo(0)
+        }
 
     @Test
-    fun validateMarginStart() = runTest {
-        overrideResource(R.bool.config_use_split_notification_shade, false)
-        overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
+    fun validateMarginStart() =
+        testScope.runTest {
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
-        val dimens = collectLastValue(underTest.configurationBasedDimensions)
+            val dimens by collectLastValue(underTest.configurationBasedDimensions)
 
-        configurationRepository.onAnyConfigurationChange()
-        runCurrent()
+            configurationRepository.onAnyConfigurationChange()
 
-        val lastDimens = dimens()!!
-
-        assertThat(lastDimens.marginStart).isEqualTo(20)
-    }
+            assertThat(dimens!!.marginStart).isEqualTo(20)
+        }
 
     @Test
-    fun validateMarginEnd() = runTest {
-        overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
+    fun validateMarginEnd() =
+        testScope.runTest {
+            overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
 
-        val dimens = collectLastValue(underTest.configurationBasedDimensions)
+            val dimens by collectLastValue(underTest.configurationBasedDimensions)
 
-        configurationRepository.onAnyConfigurationChange()
-        runCurrent()
+            configurationRepository.onAnyConfigurationChange()
 
-        val lastDimens = dimens()!!
-
-        assertThat(lastDimens.marginEnd).isEqualTo(50)
-    }
+            assertThat(dimens!!.marginEnd).isEqualTo(50)
+        }
 
     @Test
-    fun validateMarginBottom() = runTest {
-        overrideResource(R.dimen.notification_panel_margin_bottom, 50)
+    fun validateMarginBottom() =
+        testScope.runTest {
+            overrideResource(R.dimen.notification_panel_margin_bottom, 50)
 
-        val dimens = collectLastValue(underTest.configurationBasedDimensions)
+            val dimens by collectLastValue(underTest.configurationBasedDimensions)
 
-        configurationRepository.onAnyConfigurationChange()
-        runCurrent()
+            configurationRepository.onAnyConfigurationChange()
 
-        val lastDimens = dimens()!!
-
-        assertThat(lastDimens.marginBottom).isEqualTo(50)
-    }
+            assertThat(dimens!!.marginBottom).isEqualTo(50)
+        }
 
     @Test
-    fun validateMarginTopWithLargeScreenHeader() = runTest {
-        overrideResource(R.bool.config_use_large_screen_shade_header, true)
-        overrideResource(R.dimen.large_screen_shade_header_height, 50)
-        overrideResource(R.dimen.notification_panel_margin_top, 0)
+    fun validateMarginTopWithLargeScreenHeader() =
+        testScope.runTest {
+            overrideResource(R.bool.config_use_large_screen_shade_header, true)
+            overrideResource(R.dimen.large_screen_shade_header_height, 50)
+            overrideResource(R.dimen.notification_panel_margin_top, 0)
 
-        val dimens = collectLastValue(underTest.configurationBasedDimensions)
+            val dimens by collectLastValue(underTest.configurationBasedDimensions)
 
-        configurationRepository.onAnyConfigurationChange()
-        runCurrent()
+            configurationRepository.onAnyConfigurationChange()
 
-        val lastDimens = dimens()!!
-
-        assertThat(lastDimens.marginTop).isEqualTo(50)
-    }
+            assertThat(dimens!!.marginTop).isEqualTo(50)
+        }
 
     @Test
-    fun validateMarginTop() = runTest {
-        overrideResource(R.bool.config_use_large_screen_shade_header, false)
-        overrideResource(R.dimen.large_screen_shade_header_height, 50)
-        overrideResource(R.dimen.notification_panel_margin_top, 0)
+    fun validateMarginTop() =
+        testScope.runTest {
+            overrideResource(R.bool.config_use_large_screen_shade_header, false)
+            overrideResource(R.dimen.large_screen_shade_header_height, 50)
+            overrideResource(R.dimen.notification_panel_margin_top, 0)
 
-        val dimens = collectLastValue(underTest.configurationBasedDimensions)
+            val dimens by collectLastValue(underTest.configurationBasedDimensions)
 
-        configurationRepository.onAnyConfigurationChange()
-        runCurrent()
+            configurationRepository.onAnyConfigurationChange()
 
-        val lastDimens = dimens()!!
+            assertThat(dimens!!.marginTop).isEqualTo(0)
+        }
 
-        assertThat(lastDimens.marginTop).isEqualTo(0)
+    @Test
+    fun isOnLockscreen() =
+        testScope.runTest {
+            val isOnLockscreen by collectLastValue(underTest.isOnLockscreen)
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED)
+            )
+            assertThat(isOnLockscreen).isFalse()
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    to = KeyguardState.LOCKSCREEN,
+                    transitionState = TransitionState.FINISHED
+                )
+            )
+            assertThat(isOnLockscreen).isTrue()
+        }
+
+    @Test
+    fun isOnLockscreenWithoutShade() =
+        testScope.runTest {
+            val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade)
+
+            // First on AOD
+            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setQsExpansion(0f)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    to = KeyguardState.OCCLUDED,
+                    transitionState = TransitionState.FINISHED
+                )
+            )
+            assertThat(isOnLockscreenWithoutShade).isFalse()
+
+            // Now move to lockscreen
+            showLockscreen()
+
+            // While state is LOCKSCREEN, validate variations of both shade and qs expansion
+            shadeRepository.setShadeExpansion(0.1f)
+            shadeRepository.setQsExpansion(0f)
+            assertThat(isOnLockscreenWithoutShade).isFalse()
+
+            shadeRepository.setShadeExpansion(0.1f)
+            shadeRepository.setQsExpansion(0.1f)
+            assertThat(isOnLockscreenWithoutShade).isFalse()
+
+            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setQsExpansion(0.1f)
+            assertThat(isOnLockscreenWithoutShade).isFalse()
+
+            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setQsExpansion(0f)
+            assertThat(isOnLockscreenWithoutShade).isTrue()
+        }
+
+    @Test
+    fun positionOnLockscreenNotInSplitShade() =
+        testScope.runTest {
+            val position by collectLastValue(underTest.position)
+
+            // Start on lockscreen
+            showLockscreen()
+
+            // When not in split shade
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            configurationRepository.onAnyConfigurationChange()
+
+            keyguardInteractor.sharedNotificationContainerPosition.value =
+                SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+
+            assertThat(position)
+                .isEqualTo(SharedNotificationContainerPosition(top = 1f, bottom = 2f))
+        }
+
+    @Test
+    fun positionOnLockscreenInSplitShade() =
+        testScope.runTest {
+            val position by collectLastValue(underTest.position)
+
+            // Start on lockscreen
+            showLockscreen()
+
+            // When in split shade
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            configurationRepository.onAnyConfigurationChange()
+
+            keyguardInteractor.sharedNotificationContainerPosition.value =
+                SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+            runCurrent()
+
+            // Top should be overridden to 0f
+            assertThat(position)
+                .isEqualTo(SharedNotificationContainerPosition(top = 0f, bottom = 2f))
+        }
+
+    @Test
+    fun positionOnShade() =
+        testScope.runTest {
+            val position by collectLastValue(underTest.position)
+
+            // Start on lockscreen with shade expanded
+            showLockscreenWithShadeExpanded()
+
+            // When not in split shade
+            sharedNotificationContainerInteractor.setTopPosition(10f)
+
+            assertThat(position)
+                .isEqualTo(SharedNotificationContainerPosition(top = 10f, bottom = 0f))
+        }
+
+    @Test
+    fun maxNotificationsOnLockscreen() =
+        testScope.runTest {
+            whenever(
+                    notificationStackSizeCalculator.computeMaxKeyguardNotifications(
+                        any(),
+                        any(),
+                        any(),
+                        any()
+                    )
+                )
+                .thenReturn(10)
+
+            val maxNotifications by collectLastValue(underTest.maxNotifications)
+
+            showLockscreen()
+
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            configurationRepository.onAnyConfigurationChange()
+            keyguardInteractor.sharedNotificationContainerPosition.value =
+                SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+
+            assertThat(maxNotifications).isEqualTo(10)
+        }
+
+    @Test
+    fun maxNotificationsOnShade() =
+        testScope.runTest {
+            whenever(
+                    notificationStackSizeCalculator.computeMaxKeyguardNotifications(
+                        any(),
+                        any(),
+                        any(),
+                        any()
+                    )
+                )
+                .thenReturn(10)
+            val maxNotifications by collectLastValue(underTest.maxNotifications)
+
+            // Show lockscreen with shade expanded
+            showLockscreenWithShadeExpanded()
+
+            overrideResource(R.bool.config_use_split_notification_shade, false)
+            configurationRepository.onAnyConfigurationChange()
+            keyguardInteractor.sharedNotificationContainerPosition.value =
+                SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+
+            // -1 means No Limit
+            assertThat(maxNotifications).isEqualTo(-1)
+        }
+
+    private suspend fun showLockscreen() {
+        shadeRepository.setShadeExpansion(0f)
+        shadeRepository.setQsExpansion(0f)
+        keyguardTransitionRepository.sendTransitionStep(
+            TransitionStep(
+                to = KeyguardState.LOCKSCREEN,
+                transitionState = TransitionState.FINISHED
+            )
+        )
+    }
+
+    private suspend fun showLockscreenWithShadeExpanded() {
+        shadeRepository.setShadeExpansion(1f)
+        shadeRepository.setQsExpansion(0f)
+        keyguardTransitionRepository.sendTransitionStep(
+            TransitionStep(
+                to = KeyguardState.LOCKSCREEN,
+                transitionState = TransitionState.FINISHED
+            )
+        )
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index b2a1668..72cdbbc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -16,22 +16,21 @@
 
 package com.android.systemui.common.ui.data.repository
 
-import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.receiveAsFlow
 
 class FakeConfigurationRepository : ConfigurationRepository {
-    private val onAnyConfigurationChangeChannel = Channel<Unit>()
-    override val onAnyConfigurationChange: Flow<Unit> =
-        onAnyConfigurationChangeChannel.receiveAsFlow()
+    private val _onAnyConfigurationChange = MutableSharedFlow<Unit>()
+    override val onAnyConfigurationChange: Flow<Unit> = _onAnyConfigurationChange.asSharedFlow()
 
     private val _scaleForResolution = MutableStateFlow(1f)
     override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
 
     suspend fun onAnyConfigurationChange() {
-        onAnyConfigurationChangeChannel.send(Unit)
+        _onAnyConfigurationChange.tryEmit(Unit)
     }
 
     fun setScaleForResolution(scale: Float) {
@@ -41,4 +40,8 @@
     override fun getResolutionScale(): Float {
         return _scaleForResolution.value
     }
+
+    override fun getDimensionPixelSize(id: Int): Int {
+        throw IllegalStateException("Don't use for tests")
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index f13c98d..8c1ef1d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.shade.data.repository.FakeShadeRepository
 
 /**
  * Simply put, I got tired of adding a constructor argument and then having to tweak dozens of
@@ -38,6 +39,7 @@
         commandQueue: FakeCommandQueue = FakeCommandQueue(),
         bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
         configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(),
+        shadeRepository: FakeShadeRepository = FakeShadeRepository(),
     ): WithDependencies {
         return WithDependencies(
             repository = repository,
@@ -45,12 +47,14 @@
             featureFlags = featureFlags,
             bouncerRepository = bouncerRepository,
             configurationRepository = configurationRepository,
+            shadeRepository = shadeRepository,
             KeyguardInteractor(
                 repository = repository,
                 commandQueue = commandQueue,
                 featureFlags = featureFlags,
                 bouncerRepository = bouncerRepository,
                 configurationRepository = configurationRepository,
+                shadeRepository = shadeRepository,
             )
         )
     }
@@ -66,6 +70,7 @@
         val featureFlags: FakeFeatureFlags,
         val bouncerRepository: FakeKeyguardBouncerRepository,
         val configurationRepository: FakeConfigurationRepository,
+        val shadeRepository: FakeShadeRepository,
         val keyguardInteractor: KeyguardInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
index 23faaf3..05c63b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.util.mockito.mock
 import dagger.Lazy
 import kotlinx.coroutines.CoroutineScope
@@ -31,7 +30,7 @@
     @JvmStatic
     fun create(
         scope: CoroutineScope,
-        repository: KeyguardTransitionRepository = FakeKeyguardTransitionRepository(),
+        repository: FakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository(),
         keyguardInteractor: KeyguardInteractor =
             KeyguardInteractorFactory.create().keyguardInteractor,
         fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor> = Lazy {
@@ -58,7 +57,7 @@
     }
 
     data class WithDependencies(
-        val repository: KeyguardTransitionRepository,
+        val repository: FakeKeyguardTransitionRepository,
         val keyguardInteractor: KeyguardInteractor,
         val fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor>,
         val fromPrimaryBouncerTransitionInteractor: Lazy<FromPrimaryBouncerTransitionInteractor>,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index f0e1111..6b40f8e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.user.data.repository.UserRepository
 import com.android.systemui.util.mockito.mock
@@ -158,7 +159,8 @@
             commandQueue = FakeCommandQueue(),
             featureFlags = featureFlags,
             bouncerRepository = FakeKeyguardBouncerRepository(),
-            configurationRepository = FakeConfigurationRepository()
+            configurationRepository = FakeConfigurationRepository(),
+            shadeRepository = FakeShadeRepository(),
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 492e542..ccddca2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -33,6 +33,9 @@
     private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
     override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
 
+    private val _shadeExpansion = MutableStateFlow(0f)
+    override val shadeExpansion = _shadeExpansion
+
     fun setShadeModel(model: ShadeModel) {
         _shadeModel.value = model
     }
@@ -44,4 +47,8 @@
     override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
         _udfpsTransitionToFullShadeProgress.value = progress
     }
+
+    override fun setShadeExpansion(expansion: Float) {
+        _shadeExpansion.value = expansion
+    }
 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index e484a6c..97fb0e7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -4907,6 +4907,18 @@
     @GuardedBy(anyOf = {"mService", "mProcLock"})
     void updateApplicationInfoLOSP(List<String> packagesToUpdate, int userId,
             boolean updateFrameworkRes) {
+        final ArrayMap<String, ApplicationInfo> applicationInfoByPackage = new ArrayMap<>();
+        for (int i = packagesToUpdate.size() - 1; i >= 0; i--) {
+            final String packageName = packagesToUpdate.get(i);
+            final ApplicationInfo ai = mService.getPackageManagerInternal().getApplicationInfo(
+                    packageName, STOCK_PM_FLAGS, Process.SYSTEM_UID, userId);
+            if (ai != null) {
+                applicationInfoByPackage.put(packageName, ai);
+            }
+        }
+        mService.mActivityTaskManager.updateActivityApplicationInfo(userId,
+                applicationInfoByPackage);
+
         final ArrayList<WindowProcessController> targetProcesses = new ArrayList<>();
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
             final ProcessRecord app = mLruProcesses.get(i);
@@ -4921,8 +4933,7 @@
             app.getPkgList().forEachPackage(packageName -> {
                 if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
                     try {
-                        final ApplicationInfo ai = AppGlobals.getPackageManager()
-                                .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
+                        final ApplicationInfo ai = applicationInfoByPackage.get(packageName);
                         if (ai != null) {
                             if (ai.packageName.equals(app.info.packageName)) {
                                 app.info = ai;
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index c04c279..39172b8 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -25,6 +25,7 @@
 import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.MathUtils;
@@ -33,6 +34,7 @@
 import android.view.SurfaceControlHdrLayerInfoListener;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.display.BrightnessSynchronizer;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
 import com.android.server.display.DisplayManagerService.Clock;
@@ -99,6 +101,7 @@
     private boolean mIsHdrLayerPresent = false;
     // mMaxDesiredHdrSdrRatio should only be applied when there is a valid backlight->nits mapping
     private float mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+    private boolean mForceHbmChangeCallback = false;
     private boolean mIsBlockedByLowPowerMode = false;
     private int mWidth;
     private int mHeight;
@@ -484,7 +487,8 @@
     private void updateHbmMode() {
         int newHbmMode = calculateHighBrightnessMode();
         updateHbmStats(newHbmMode);
-        if (mHbmMode != newHbmMode) {
+        if (mHbmMode != newHbmMode || mForceHbmChangeCallback) {
+            mForceHbmChangeCallback = false;
             mHbmMode = newHbmMode;
             mHbmChangeCallback.run();
         }
@@ -600,26 +604,32 @@
         public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
                 int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio) {
             mHandler.post(() -> {
+                Trace.traceBegin(Trace.TRACE_TAG_POWER, "HBMController#onHdrInfoChanged");
                 mIsHdrLayerPresent = numberOfHdrLayers > 0
                         && (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
                                    * mHbmData.minimumHdrPercentOfScreen);
 
-                final float candidateDesiredHdrSdrRatio =
+                float candidateDesiredHdrSdrRatio =
                         mIsHdrLayerPresent && mHdrBrightnessCfg != null
                                 ? maxDesiredHdrSdrRatio
                                 : DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
 
-                if (candidateDesiredHdrSdrRatio >= 1.0f) {
-                    mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
-                } else {
+                if (candidateDesiredHdrSdrRatio < 1.0f) {
                     Slog.w(TAG, "Ignoring invalid desired HDR/SDR Ratio: "
                             + candidateDesiredHdrSdrRatio);
-                    mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+                    candidateDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
+                }
+
+                if (!BrightnessSynchronizer.floatEquals(
+                        mMaxDesiredHdrSdrRatio, candidateDesiredHdrSdrRatio)) {
+                    mForceHbmChangeCallback = true;
+                    mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
                 }
 
                 // Calling the brightness update so that we can recalculate
                 // brightness with HDR in mind.
                 onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             });
         }
     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7897195..b01a89e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -72,7 +72,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
@@ -94,6 +93,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
 
 /**
  * Manages all permissions and handles permissions related tasks.
@@ -233,11 +233,11 @@
         }
 
         if (checkPermissionDelegate == null) {
-            return mPermissionManagerServiceImpl.checkPermission(packageName, permissionName,
-                    deviceId, userId);
+            return mPermissionManagerServiceImpl.checkPermission(
+                    packageName, permissionName, userId);
         }
-        return checkPermissionDelegate.checkPermission(packageName, permissionName,
-                deviceId, userId, mPermissionManagerServiceImpl::checkPermission);
+        return checkPermissionDelegate.checkPermission(packageName, permissionName, userId,
+                mPermissionManagerServiceImpl::checkPermission);
     }
 
     @Override
@@ -254,10 +254,10 @@
         }
 
         if (checkPermissionDelegate == null)  {
-            return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName, deviceId);
+            return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName);
         }
         return checkPermissionDelegate.checkUidPermission(uid, permissionName,
-                deviceId, mPermissionManagerServiceImpl::checkUidPermission);
+                mPermissionManagerServiceImpl::checkUidPermission);
     }
 
     @Override
@@ -511,14 +511,14 @@
     public int getPermissionFlags(String packageName, String permissionName, int deviceId,
             int userId) {
         return mPermissionManagerServiceImpl
-                .getPermissionFlags(packageName, permissionName, deviceId, userId);
+                .getPermissionFlags(packageName, permissionName, userId);
     }
 
     @Override
     public void updatePermissionFlags(String packageName, String permissionName, int flagMask,
             int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
         mPermissionManagerServiceImpl.updatePermissionFlags(packageName, permissionName, flagMask,
-                flagValues, checkAdjustPolicyFlagPermission, deviceId, userId);
+                flagValues, checkAdjustPolicyFlagPermission, userId);
     }
 
     @Override
@@ -560,15 +560,14 @@
     @Override
     public void grantRuntimePermission(String packageName, String permissionName, int deviceId,
             int userId) {
-        mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName,
-                deviceId, userId);
+        mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName, userId);
     }
 
     @Override
     public void revokeRuntimePermission(String packageName, String permissionName, int deviceId,
             int userId, String reason) {
         mPermissionManagerServiceImpl.revokeRuntimePermission(packageName, permissionName,
-                deviceId, userId, reason);
+                userId, reason);
     }
 
     @Override
@@ -581,14 +580,14 @@
     public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
             int deviceId, int userId) {
         return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
-                permissionName, deviceId, userId);
+                permissionName, userId);
     }
 
     @Override
     public boolean isPermissionRevokedByPolicy(String packageName, String permissionName,
             int deviceId, int userId) {
-        return mPermissionManagerServiceImpl.isPermissionRevokedByPolicy(packageName,
-                permissionName, deviceId, userId);
+        return mPermissionManagerServiceImpl
+                .isPermissionRevokedByPolicy(packageName, permissionName, userId);
     }
 
     @Override
@@ -869,7 +868,6 @@
          *
          * @param packageName the name of the package to be checked
          * @param permissionName the name of the permission to be checked
-         * @param deviceId The device ID
          * @param userId the user ID
          * @param superImpl the original implementation that can be delegated to
          * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
@@ -878,21 +876,20 @@
          * @see android.content.pm.PackageManager#checkPermission(String, String)
          */
         int checkPermission(@NonNull String packageName, @NonNull String permissionName,
-                int deviceId, @UserIdInt int userId,
-                @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl);
+                @UserIdInt int userId,
+                @NonNull TriFunction<String, String, Integer, Integer> superImpl);
 
         /**
          * Check whether the given UID has been granted the specified permission.
          *
          * @param uid the UID to be checked
          * @param permissionName the name of the permission to be checked
-         * @param deviceId The device ID
          * @param superImpl the original implementation that can be delegated to
          * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
          * the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise
          */
-        int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
-                TriFunction<Integer, String, Integer, Integer> superImpl);
+        int checkUidPermission(int uid, @NonNull String permissionName,
+                BiFunction<Integer, String, Integer> superImpl);
 
         /**
          * @return list of delegated permissions
@@ -921,32 +918,31 @@
 
         @Override
         public int checkPermission(@NonNull String packageName, @NonNull String permissionName,
-                int deviceId, int userId,
-                @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl) {
+                int userId, @NonNull TriFunction<String, String, Integer, Integer> superImpl) {
             if (mDelegatedPackageName.equals(packageName)
                     && isDelegatedPermission(permissionName)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply("com.android.shell", permissionName, deviceId, userId);
+                    return superImpl.apply("com.android.shell", permissionName, userId);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            return superImpl.apply(packageName, permissionName, deviceId, userId);
+            return superImpl.apply(packageName, permissionName, userId);
         }
 
         @Override
-        public int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
-                @NonNull TriFunction<Integer, String, Integer, Integer> superImpl) {
+        public int checkUidPermission(int uid, @NonNull String permissionName,
+                @NonNull BiFunction<Integer, String, Integer> superImpl) {
             if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply(Process.SHELL_UID, permissionName, deviceId);
+                    return superImpl.apply(Process.SHELL_UID, permissionName);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            return superImpl.apply(uid, permissionName, deviceId);
+            return superImpl.apply(uid, permissionName);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 6764e08..4353c57 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -681,7 +681,7 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+    public int getPermissionFlags(String packageName, String permName, int userId) {
         final int callingUid = Binder.getCallingUid();
         return getPermissionFlagsInternal(packageName, permName, callingUid, userId);
     }
@@ -724,7 +724,7 @@
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
         final int callingUid = Binder.getCallingUid();
         boolean overridePolicy = false;
 
@@ -908,12 +908,8 @@
         }
     }
 
-    private int checkPermission(String pkgName, String permName, int userId) {
-        return checkPermission(pkgName, permName, Context.DEVICE_ID_DEFAULT, userId);
-    }
-
     @Override
-    public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+    public int checkPermission(String pkgName, String permName, int userId) {
         if (!mUserManagerInt.exists(userId)) {
             return PackageManager.PERMISSION_DENIED;
         }
@@ -979,12 +975,8 @@
         return true;
     }
 
-    private int checkUidPermission(int uid, String permName) {
-        return checkUidPermission(uid, permName, Context.DEVICE_ID_DEFAULT);
-    }
-
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
+    public int checkUidPermission(int uid, String permName) {
         final int userId = UserHandle.getUserId(uid);
         if (!mUserManagerInt.exists(userId)) {
             return PackageManager.PERMISSION_DENIED;
@@ -1303,8 +1295,7 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName, int deviceId,
-            int userId) {
+    public void grantRuntimePermission(String packageName, String permName, final int userId) {
         final int callingUid = Binder.getCallingUid();
         final boolean overridePolicy =
                 checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
@@ -1477,11 +1468,11 @@
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName, int deviceId,
-            int userId, String reason) {
+    public void revokeRuntimePermission(String packageName, String permName, int userId,
+            String reason) {
         final int callingUid = Binder.getCallingUid();
         final boolean overridePolicy =
-                checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY, deviceId)
+                checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
                         == PackageManager.PERMISSION_GRANTED;
 
         revokeRuntimePermissionInternal(packageName, permName, overridePolicy, callingUid, userId,
@@ -1868,7 +1859,7 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, @UserIdInt int userId) {
+            @UserIdInt int userId) {
         final int callingUid = Binder.getCallingUid();
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingPermission(
@@ -1931,8 +1922,7 @@
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
-            int userId) {
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -2069,8 +2059,8 @@
                     continue;
                 }
                 boolean isSystemOrPolicyFixed = (getPermissionFlags(newPackage.getPackageName(),
-                        permInfo.name, Context.DEVICE_ID_DEFAULT, userId) & (
-                        FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_POLICY_FIXED)) != 0;
+                        permInfo.name, userId) & (FLAG_PERMISSION_SYSTEM_FIXED
+                        | FLAG_PERMISSION_POLICY_FIXED)) != 0;
                 if (isSystemOrPolicyFixed) {
                     continue;
                 }
@@ -2236,8 +2226,7 @@
                 for (final int userId : userIds) {
                     final int permissionState = checkPermission(packageName, permName,
                             userId);
-                    final int flags = getPermissionFlags(packageName, permName,
-                            Context.DEVICE_ID_DEFAULT, userId);
+                    final int flags = getPermissionFlags(packageName, permName, userId);
                     final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
                             | FLAG_PERMISSION_POLICY_FIXED
                             | FLAG_PERMISSION_GRANTED_BY_DEFAULT
@@ -5133,7 +5122,8 @@
 
     @NonNull
     @Override
-    public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
+    public Set<String> getGrantedPermissions(@NonNull String packageName,
+            @UserIdInt int userId) {
         Objects.requireNonNull(packageName, "packageName");
         Preconditions.checkArgumentNonNegative(userId, "userId");
         return getGrantedPermissionsInternal(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 2d824aa..128f847 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,6 +25,7 @@
 import android.content.pm.PermissionInfo;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
 
 import com.android.server.pm.pkg.AndroidPackage;
@@ -136,16 +137,14 @@
     void removePermission(String permName);
 
     /**
-     * Gets the permission state flags associated with a permission.
+     * Gets the state flags associated with a permission.
      *
      * @param packageName the package name for which to get the flags
      * @param permName the permission for which to get the flags
-     * @param deviceId The device for which to get the flags
      * @param userId the user for which to get permission flags
      * @return the permission flags
      */
-    int getPermissionFlags(String packageName, String permName, int deviceId,
-            @UserIdInt int userId);
+    int getPermissionFlags(String packageName, String permName, int userId);
 
     /**
      * Updates the flags associated with a permission by replacing the flags in the specified mask
@@ -155,11 +154,10 @@
      * @param permName The permission for which to update the flags
      * @param flagMask The flags which to replace
      * @param flagValues The flags with which to replace
-     * @param deviceId The device for which to update the permission flags
      * @param userId The user for which to update the permission flags
      */
-    void updatePermissionFlags(String packageName, String permName, int flagMask, int flagValues,
-            boolean checkAdjustPolicyFlagPermission, int deviceId, @UserIdInt int userId);
+    void updatePermissionFlags(String packageName, String permName, int flagMask,
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
 
     /**
      * Update the permission flags for all packages and runtime permissions of a user in order
@@ -293,13 +291,11 @@
      *
      * @param packageName the package to which to grant the permission
      * @param permName the permission name to grant
-     * @param deviceId the device for which to grant the permission
      * @param userId the user for which to grant the permission
      *
-     * @see #revokeRuntimePermission(String, String, int, int, String)
+     * @see #revokeRuntimePermission(String, String, android.os.UserHandle, String)
      */
-    void grantRuntimePermission(String packageName, String permName, int deviceId,
-            @UserIdInt int userId);
+    void grantRuntimePermission(String packageName, String permName, int userId);
 
     /**
      * Revoke a runtime permission that was previously granted by
@@ -314,14 +310,13 @@
      *
      * @param packageName the package from which to revoke the permission
      * @param permName the permission name to revoke
-     * @param deviceId the device for which to revoke the permission
      * @param userId the user for which to revoke the permission
      * @param reason the reason for the revoke, or {@code null} for unspecified
      *
-     * @see #grantRuntimePermission(String, String, int, int)
+     * @see #grantRuntimePermission(String, String, android.os.UserHandle)
      */
-    void revokeRuntimePermission(String packageName, String permName, int deviceId,
-            @UserIdInt int userId, String reason);
+    void revokeRuntimePermission(String packageName, String permName, int userId,
+            String reason);
 
     /**
      * Revoke the POST_NOTIFICATIONS permission, without killing the app. This method must ONLY BE
@@ -338,29 +333,24 @@
      * does not clearly communicate to the user what would be the benefit from grating this
      * permission.
      *
-     * @param packageName the package name
      * @param permName a permission your app wants to request
-     * @param deviceId the device for which to check the permission
-     * @param userId the user for which to check the permission
      * @return whether you can show permission rationale UI
      */
     boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, @UserIdInt int userId);
+            @UserIdInt int userId);
 
     /**
-     * Checks whether a particular permission has been revoked for a package by policy. Typically,
+     * Checks whether a particular permissions has been revoked for a package by policy. Typically
      * the device owner or the profile owner may apply such a policy. The user cannot grant policy
      * revoked permissions, hence the only way for an app to get such a permission is by a policy
      * change.
      *
      * @param packageName the name of the package you are checking against
      * @param permName the name of the permission you are checking for
-     * @param deviceId the device for which you are checking the permission
-     * @param userId the device for which you are checking the permission
+     *
      * @return whether the permission is restricted by policy
      */
-    boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
-            @UserIdInt int userId);
+    boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId);
 
     /**
      * Get set of permissions that have been split into more granular or dependent permissions.
@@ -383,25 +373,14 @@
     List<SplitPermissionInfoParcelable> getSplitPermissions();
 
     /**
-     * Check whether a permission is granted or not to a package.
-     *
-     * @param pkgName package name
-     * @param permName permission name
-     * @param deviceId device ID
-     * @param userId user ID
-     * @return permission result {@link PackageManager.PermissionResult}
+     * TODO:theianchen add doc describing this is the old checkPermissionImpl
      */
-    int checkPermission(String pkgName, String permName, int deviceId, @UserIdInt int userId);
+    int checkPermission(String pkgName, String permName, int userId);
 
     /**
-     * Check whether a permission is granted or not to an UID.
-     *
-     * @param uid UID
-     * @param permName permission name
-     * @param deviceId device ID
-     * @return permission result {@link PackageManager.PermissionResult}
+     * TODO:theianchen add doc describing this is the old checkUidPermissionImpl
      */
-    int checkUidPermission(int uid, String permName, int deviceId);
+    int checkUidPermission(int uid, String permName);
 
     /**
      * Get all the package names requesting app op permissions.
@@ -421,11 +400,15 @@
             @UserIdInt int userId);
 
     /**
-     * Reset the runtime permission state changes for a package for all devices.
+     * Reset the runtime permission state changes for a package.
      *
      * TODO(zhanghai): Turn this into package change callback?
+     *
+     * @param pkg the package
+     * @param userId the user ID
      */
-    void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId);
+    void resetRuntimePermissions(@NonNull AndroidPackage pkg,
+            @UserIdInt int userId);
 
     /**
      * Reset the runtime permission state changes for all packages in a user.
@@ -466,8 +449,8 @@
     /**
      * Get all the permissions granted to a package.
      *
-     * @param packageName package name
-     * @param userId user ID
+     * @param packageName the name of the package
+     * @param userId the user ID
      * @return the names of the granted permissions
      */
     @NonNull
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index dacb8c6..7f98e21 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -120,21 +120,21 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+    public int getPermissionFlags(String packageName, String permName, int userId) {
         Log.i(LOG_TAG, "getPermissionFlags(packageName = " + packageName + ", permName = "
-                + permName + ", deviceId = " + deviceId +  ", userId = " + userId + ")");
-        return mService.getPermissionFlags(packageName, permName, deviceId, userId);
+                + permName + ", userId = " + userId + ")");
+        return mService.getPermissionFlags(packageName, permName, userId);
     }
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
         Log.i(LOG_TAG, "updatePermissionFlags(packageName = " + packageName + ", permName = "
                 + permName + ", flagMask = " + flagMask + ", flagValues = " + flagValues
                 + ", checkAdjustPolicyFlagPermission = " + checkAdjustPolicyFlagPermission
-                + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+                + ", userId = " + userId + ")");
         mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                checkAdjustPolicyFlagPermission, deviceId, userId);
+                checkAdjustPolicyFlagPermission, userId);
     }
 
     @Override
@@ -182,20 +182,18 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName, int deviceId,
-            int userId) {
+    public void grantRuntimePermission(String packageName, String permName, int userId) {
         Log.i(LOG_TAG, "grantRuntimePermission(packageName = " + packageName + ", permName = "
-                + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
-        mService.grantRuntimePermission(packageName, permName, deviceId, userId);
+                + permName + ", userId = " + userId + ")");
+        mService.grantRuntimePermission(packageName, permName, userId);
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName, int deviceId,
-            int userId, String reason) {
+    public void revokeRuntimePermission(String packageName, String permName, int userId,
+            String reason) {
         Log.i(LOG_TAG, "revokeRuntimePermission(packageName = " + packageName + ", permName = "
-                + permName + ", deviceId = " + deviceId + ", userId = " + userId
-                + ", reason = " + reason + ")");
-        mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+                + permName + ", userId = " + userId + ", reason = " + reason + ")");
+        mService.revokeRuntimePermission(packageName, permName, userId, reason);
     }
 
     @Override
@@ -207,20 +205,17 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, int userId) {
+            int userId) {
         Log.i(LOG_TAG, "shouldShowRequestPermissionRationale(packageName = " + packageName
-                + ", permName = " + permName + ", deviceId = " + deviceId
-                +  ", userId = " + userId + ")");
-        return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
-                userId);
+                + ", permName = " + permName + ", userId = " + userId + ")");
+        return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
-            int userId) {
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
         Log.i(LOG_TAG, "isPermissionRevokedByPolicy(packageName = " + packageName + ", permName = "
-                + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
-        return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
+                + permName + ", userId = " + userId + ")");
+        return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
     }
 
     @Override
@@ -230,17 +225,16 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+    public int checkPermission(String pkgName, String permName, int userId) {
         Log.i(LOG_TAG, "checkPermission(pkgName = " + pkgName + ", permName = " + permName
-                + ", deviceId = " + deviceId + ", userId = " + userId + ")");
-        return mService.checkPermission(pkgName, permName, deviceId, userId);
+                + ", userId = " + userId + ")");
+        return mService.checkPermission(pkgName, permName, userId);
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
-        Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
-                + ", deviceId = " + deviceId + ")");
-        return mService.checkUidPermission(uid, permName, deviceId);
+    public int checkUidPermission(int uid, String permName) {
+        Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName + ")");
+        return mService.checkUidPermission(uid, permName);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index 35d165b..d4c6d42 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -153,10 +153,9 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, int deviceId,
-            @UserIdInt int userId) {
-        int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
-        int newVal = mNewImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
+    public int getPermissionFlags(String packageName, String permName, int userId) {
+        int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, userId);
+        int newVal = mNewImplementation.getPermissionFlags(packageName, permName, userId);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("getPermissionFlags");
@@ -166,12 +165,11 @@
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId,
-            @UserIdInt int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
         mOldImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                checkAdjustPolicyFlagPermission, deviceId, userId);
+                checkAdjustPolicyFlagPermission, userId);
         mNewImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                checkAdjustPolicyFlagPermission, deviceId, userId);
+                checkAdjustPolicyFlagPermission, userId);
     }
 
     @Override
@@ -236,17 +234,16 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName, int deviceId,
-            @UserIdInt int userId) {
-        mOldImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
-        mNewImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
+    public void grantRuntimePermission(String packageName, String permName, int userId) {
+        mOldImplementation.grantRuntimePermission(packageName, permName, userId);
+        mNewImplementation.grantRuntimePermission(packageName, permName, userId);
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName, int deviceId,
-            @UserIdInt int userId, String reason) {
-        mOldImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
-        mNewImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+    public void revokeRuntimePermission(String packageName, String permName, int userId,
+            String reason) {
+        mOldImplementation.grantRuntimePermission(packageName, permName, userId);
+        mNewImplementation.grantRuntimePermission(packageName, permName, userId);
     }
 
     @Override
@@ -258,11 +255,11 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, @UserIdInt int userId) {
-        boolean oldVal = mOldImplementation.shouldShowRequestPermissionRationale(packageName,
-                permName, deviceId,  userId);
-        boolean newVal = mNewImplementation.shouldShowRequestPermissionRationale(packageName,
-                permName, deviceId, userId);
+            int userId) {
+        boolean oldVal = mOldImplementation
+                .shouldShowRequestPermissionRationale(packageName, permName, userId);
+        boolean newVal = mNewImplementation
+                .shouldShowRequestPermissionRationale(packageName, permName, userId);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("shouldShowRequestPermissionRationale");
@@ -271,12 +268,11 @@
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
-            @UserIdInt int userId) {
-        boolean oldVal = mOldImplementation.isPermissionRevokedByPolicy(packageName, permName,
-                deviceId, userId);
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+        boolean oldVal = mOldImplementation
+                .isPermissionRevokedByPolicy(packageName, permName, userId);
         boolean newVal = mNewImplementation.isPermissionRevokedByPolicy(packageName, permName,
-                deviceId, userId);
+                userId);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("isPermissionRevokedByPolicy");
@@ -296,9 +292,9 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
-        int oldVal = mOldImplementation.checkPermission(pkgName, permName, deviceId, userId);
-        int newVal = mNewImplementation.checkPermission(pkgName, permName, deviceId, userId);
+    public int checkPermission(String pkgName, String permName, int userId) {
+        int oldVal = mOldImplementation.checkPermission(pkgName, permName, userId);
+        int newVal = mNewImplementation.checkPermission(pkgName, permName, userId);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("checkPermission");
@@ -307,9 +303,9 @@
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
-        int oldVal = mOldImplementation.checkUidPermission(uid, permName, deviceId);
-        int newVal = mNewImplementation.checkUidPermission(uid, permName, deviceId);
+    public int checkUidPermission(int uid, String permName) {
+        int oldVal = mOldImplementation.checkUidPermission(uid, permName);
+        int newVal = mNewImplementation.checkUidPermission(uid, permName);
 
         if (!Objects.equals(oldVal, newVal)) {
             signalImplDifference("checkUidPermission");
@@ -376,7 +372,7 @@
 
     @NonNull
     @Override
-    public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
+    public Set<String> getGrantedPermissions(@NonNull String packageName, int userId) {
         Set<String> oldVal = mOldImplementation.getGrantedPermissions(packageName, userId);
         Set<String> newVal = mNewImplementation.getGrantedPermissions(packageName, userId);
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index cbeede0..4e72fae 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -158,10 +158,10 @@
     }
 
     @Override
-    public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+    public int getPermissionFlags(String packageName, String permName, int userId) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
         try {
-            return mService.getPermissionFlags(packageName, permName, deviceId, userId);
+            return mService.getPermissionFlags(packageName, permName, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -169,12 +169,12 @@
 
     @Override
     public void updatePermissionFlags(String packageName, String permName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
         try {
             mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
-                    checkAdjustPolicyFlagPermission, deviceId, userId);
+                    checkAdjustPolicyFlagPermission, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -253,24 +253,23 @@
     }
 
     @Override
-    public void grantRuntimePermission(String packageName, String permName, int deviceId,
-            int userId) {
+    public void grantRuntimePermission(String packageName, String permName, int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
         try {
-            mService.grantRuntimePermission(packageName, permName, deviceId, userId);
+            mService.grantRuntimePermission(packageName, permName, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permName, int deviceId,
-            int userId, String reason) {
+    public void revokeRuntimePermission(String packageName, String permName, int userId,
+            String reason) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
         try {
-            mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+            mService.revokeRuntimePermission(packageName, permName, userId, reason);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -289,24 +288,22 @@
 
     @Override
     public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
-            int deviceId, int userId) {
+            int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
         try {
-            return mService.shouldShowRequestPermissionRationale(
-                    packageName, permName, deviceId, userId);
+            return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
     }
 
     @Override
-    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
-            int userId) {
+    public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
         Trace.traceBegin(TRACE_TAG,
                 "TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
         try {
-            return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
+            return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
@@ -324,20 +321,20 @@
     }
 
     @Override
-    public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+    public int checkPermission(String pkgName, String permName, int userId) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
         try {
-            return mService.checkPermission(pkgName, permName, deviceId, userId);
+            return mService.checkPermission(pkgName, permName, userId);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
     }
 
     @Override
-    public int checkUidPermission(int uid, String permName, int deviceId) {
+    public int checkUidPermission(int uid, String permName) {
         Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
         try {
-            return mService.checkUidPermission(uid, permName, deviceId);
+            return mService.checkUidPermission(uid, permName);
         } finally {
             Trace.traceEnd(TRACE_TAG);
         }
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index 3b4b20f..fbad762 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -322,11 +322,26 @@
     interface Clock {
         /** Returns milliseconds since boot, including time spent in sleep. */
         long elapsedRealtime();
+
+        /** Returns milliseconds since boot, not counting time spent in deep sleep. */
+        long uptimeMillis();
+    }
+
+    private static class RealClock implements Clock {
+        @Override
+        public long elapsedRealtime() {
+            return SystemClock.elapsedRealtime();
+        }
+
+        @Override
+        public long uptimeMillis() {
+            return SystemClock.uptimeMillis();
+        }
     }
 
     public LowPowerStandbyController(Context context, Looper looper) {
-        this(context, looper, SystemClock::elapsedRealtime,
-                new DeviceConfigWrapper(), () -> ActivityManager.getService(),
+        this(context, looper, new RealClock(), new DeviceConfigWrapper(),
+                () -> ActivityManager.getService(),
                 new File(Environment.getDataSystemDirectory(), "low_power_standby_policy.xml"));
     }
 
@@ -572,9 +587,9 @@
 
     @GuardedBy("mLock")
     private void updateActiveLocked() {
-        final long now = mClock.elapsedRealtime();
+        final long nowElapsed = mClock.elapsedRealtime();
         final boolean standbyTimeoutExpired =
-                (now - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig;
+                (nowElapsed - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig;
         final boolean maintenanceMode = mIdleSinceNonInteractive && !mIsDeviceIdle;
         final boolean newActive =
                 mForceActive || (mIsEnabled && !mIsInteractive && standbyTimeoutExpired
@@ -600,11 +615,11 @@
         if (DEBUG) {
             Slog.d(TAG, "onNonInteractive");
         }
-        final long now = mClock.elapsedRealtime();
+        final long nowElapsed = mClock.elapsedRealtime();
         synchronized (mLock) {
             mIsInteractive = false;
             mIsDeviceIdle = false;
-            mLastInteractiveTimeElapsed = now;
+            mLastInteractiveTimeElapsed = nowElapsed;
 
             if (mStandbyTimeoutConfig > 0) {
                 scheduleStandbyTimeoutAlarmLocked();
@@ -630,7 +645,7 @@
 
     @GuardedBy("mLock")
     private void scheduleStandbyTimeoutAlarmLocked() {
-        final long nextAlarmTime = SystemClock.elapsedRealtime() + mStandbyTimeoutConfig;
+        final long nextAlarmTime = mClock.elapsedRealtime() + mStandbyTimeoutConfig;
         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                 nextAlarmTime, "LowPowerStandbyController.StandbyTimeout",
                 mOnStandbyTimeoutExpired, mHandler);
@@ -748,9 +763,8 @@
 
     @GuardedBy("mLock")
     private void enqueueNotifyPolicyChangedLocked() {
-        final long now = mClock.elapsedRealtime();
         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_POLICY_CHANGED, getPolicy());
-        mHandler.sendMessageAtTime(msg, now);
+        mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
     }
 
     private void notifyPolicyChanged(LowPowerStandbyPolicy policy) {
@@ -775,9 +789,8 @@
 
     @GuardedBy("mLock")
     private void enqueueNotifyActiveChangedLocked() {
-        final long now = mClock.elapsedRealtime();
         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ACTIVE_CHANGED, mIsActive);
-        mHandler.sendMessageAtTime(msg, now);
+        mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
     }
 
     /** Notify other system components about the updated Low Power Standby active state */
@@ -1308,7 +1321,6 @@
 
     @GuardedBy("mLock")
     private void enqueueNotifyAllowlistChangedLocked() {
-        final long now = mClock.elapsedRealtime();
         final int[] allowlistUids = getAllowlistUidsLocked();
 
         if (DEBUG) {
@@ -1317,7 +1329,7 @@
         }
 
         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ALLOWLIST_CHANGED, allowlistUids);
-        mHandler.sendMessageAtTime(msg, now);
+        mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
     }
 
     private void notifyAllowlistChanged(int[] allowlistUids) {
@@ -1334,14 +1346,12 @@
 
     @GuardedBy("mLock")
     private void enqueueNotifyStandbyPortsChangedLocked() {
-        final long now = mClock.elapsedRealtime();
-
         if (DEBUG) {
             Slog.d(TAG, "enqueueNotifyStandbyPortsChangedLocked");
         }
 
         final Message msg = mHandler.obtainMessage(MSG_NOTIFY_STANDBY_PORTS_CHANGED);
-        mHandler.sendMessageAtTime(msg, now);
+        mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
     }
 
     private void notifyStandbyPortsChanged() {
@@ -1448,12 +1458,11 @@
         public void onForegroundStateChanged(IBinder serviceToken, String packageName,
                 int userId, boolean isForeground) {
             try {
-                final long now = mClock.elapsedRealtime();
                 final int uid = mContext.getPackageManager()
                         .getPackageUidAsUser(packageName, userId);
                 final Message message =
                         mHandler.obtainMessage(MSG_FOREGROUND_SERVICE_STATE_CHANGED, uid, 0);
-                mHandler.sendMessageAtTime(message, now);
+                mHandler.sendMessageAtTime(message, mClock.uptimeMillis());
             } catch (PackageManager.NameNotFoundException e) {
                 if (DEBUG) {
                     Slog.d(TAG, "onForegroundStateChanged: Unknown package: " + packageName
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index aafff2c..d430dda 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -615,7 +615,15 @@
     @Override
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
         synchronized (mGlobalLock) {
-            return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
+            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+            if (r == null) {
+                return INVALID_TASK_ID;
+            }
+            final Task task = r.getTask();
+            if (onlyRoot) {
+                return task.getRootActivity() == r ? task.mTaskId : INVALID_TASK_ID;
+            }
+            return task.mTaskId;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f776fac..9eec5f8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -584,20 +584,11 @@
     // Tracking splash screen status from previous activity
     boolean mSplashScreenStyleSolidColor = false;
 
-    Drawable mEnterpriseThumbnailDrawable;
-
     boolean mPauseSchedulePendingForPip = false;
 
     // Gets set to indicate that the activity is currently being auto-pipped.
     boolean mAutoEnteringPip = false;
 
-    private void updateEnterpriseThumbnailDrawable(Context context) {
-        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-        mEnterpriseThumbnailDrawable = dpm.getResources().getDrawable(
-                WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
-                () -> context.getDrawable(R.drawable.ic_corp_badge));
-    }
-
     static final int LAUNCH_SOURCE_TYPE_SYSTEM = 1;
     static final int LAUNCH_SOURCE_TYPE_HOME = 2;
     static final int LAUNCH_SOURCE_TYPE_SYSTEMUI = 3;
@@ -2212,8 +2203,6 @@
 
         mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
 
-        updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
-
         boolean appActivityEmbeddingEnabled = false;
         try {
             appActivityEmbeddingEnabled = WindowManager.hasWindowExtensionsEnabled()
@@ -3397,7 +3386,7 @@
 
         rootTask.moveToFront(reason, task);
         // Report top activity change to tracking services and WM
-        if (mRootWindowContainer.getTopResumedActivity() == this) {
+        if (mState == RESUMED && mRootWindowContainer.getTopResumedActivity() == this) {
             mAtmService.setLastResumedActivityUncheckLocked(this, reason);
         }
         return true;
@@ -7122,15 +7111,18 @@
         return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED;
     }
 
+    /**
+     * Returns the task id of the activity token. If onlyRoot=true is specified, it will
+     * return a valid id only if the activity is root or the activity is immediately above
+     * the first non-relinquish-identity activity.
+     * TODO(b/297476786): Clarify the use cases about when should get the bottom activity
+     *                    or the first non-relinquish-identity activity from bottom.
+     */
     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r == null || r.getParent() == null) {
             return INVALID_TASK_ID;
         }
-        return getTaskForActivityLocked(r, onlyRoot);
-    }
-
-    static int getTaskForActivityLocked(ActivityRecord r, boolean onlyRoot) {
         final Task task = r.task;
         if (onlyRoot && r.compareTo(task.getRootActivity(
                 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) {
@@ -7711,9 +7703,16 @@
             return;
         }
         final Rect frame = win.getRelativeFrame();
-        final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
-                ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
-                : mEnterpriseThumbnailDrawable;
+        final Context context = mAtmService.getUiContext();
+        final Drawable thumbnailDrawable;
+        if (task.mUserId == mWmService.mCurrentUserId) {
+            thumbnailDrawable = context.getDrawable(R.drawable.ic_account_circle);
+        } else {
+            final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+            thumbnailDrawable = dpm.getResources().getDrawable(
+                    WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
+                    () -> context.getDrawable(R.drawable.ic_corp_badge));
+        }
         final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
                 .createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
         if (thumbnail == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fb62412..59159bb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4588,6 +4588,20 @@
     }
 
     /**
+     * Updates the {@link ApplicationInfo}s of the package activities th that are attached in the
+     * WM hierarchy.
+     */
+    public void updateActivityApplicationInfo(int userId,
+            ArrayMap<String, ApplicationInfo> applicationInfoByPackage) {
+        synchronized (mGlobalLock) {
+            if (mRootWindowContainer != null) {
+                mRootWindowContainer.updateActivityApplicationInfo(userId,
+                        applicationInfoByPackage);
+            }
+        }
+    }
+
+    /**
      * Update the asset configuration and increase the assets sequence number.
      * @param processes the processes that needs to update the asset configuration
      */
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2eec58b..6b4cc25 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3172,6 +3172,20 @@
         });
     }
 
+    void updateActivityApplicationInfo(int userId,
+            ArrayMap<String, ApplicationInfo> applicationInfoByPackage) {
+        forAllActivities(r -> {
+            if (r.mUserId != userId) {
+                return;
+            }
+
+            final ApplicationInfo aInfo = applicationInfoByPackage.get(r.packageName);
+            if (aInfo != null) {
+                r.updateApplicationInfo(aInfo);
+            }
+        });
+    }
+
     void finishVoiceTask(IVoiceInteractionSession session) {
         final IBinder binder = session.asBinder();
         forAllLeafTasks(t -> t.finishIfVoiceTask(binder), true /* traverseTopToBottom */);
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 6a349e2..17474fb 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -26,7 +26,6 @@
 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
 import com.android.server.permission.access.immutable.IndexedMap
 import com.android.server.permission.access.permission.AppIdPermissionPolicy
-import com.android.server.permission.access.permission.DevicePermissionPolicy
 import com.android.server.permission.access.util.attributeInt
 import com.android.server.permission.access.util.attributeInterned
 import com.android.server.permission.access.util.forEachTag
@@ -47,7 +46,6 @@
                 getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] = policy
             }
             addPolicy(AppIdPermissionPolicy())
-            addPolicy(DevicePermissionPolicy())
             addPolicy(AppIdAppOpPolicy())
             addPolicy(PackageAppOpPolicy())
         } as IndexedMap<String, IndexedMap<String, SchemePolicy>>
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index 94c878a..4ec32ea 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -329,18 +329,6 @@
 private typealias AppIdPermissionFlagsReference =
     MutableReference<AppIdPermissionFlags, MutableAppIdPermissionFlags>
 
-
-typealias DevicePermissionFlags =
-    IndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
-typealias MutableDevicePermissionFlags =
-    MutableIndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
-typealias AppIdDevicePermissionFlags =
-    IntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
-typealias MutableAppIdDevicePermissionFlags =
-    MutableIntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
-private typealias AppIdDevicePermissionFlagsReference =
-    MutableReference<AppIdDevicePermissionFlags, MutableAppIdDevicePermissionFlags>
-
 typealias AppIdAppOpModes =
     IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
 typealias MutableAppIdAppOpModes =
@@ -358,7 +346,6 @@
 sealed class UserState(
     internal val packageVersionsReference: PackageVersionsReference,
     internal val appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
-    internal val appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
     internal val appIdAppOpModesReference: AppIdAppOpModesReference,
     internal val packageAppOpModesReference: PackageAppOpModesReference,
     defaultPermissionGrantFingerprint: String?,
@@ -370,9 +357,6 @@
     val appIdPermissionFlags: AppIdPermissionFlags
         get() = appIdPermissionFlagsReference.get()
 
-    val appIdDevicePermissionFlags: AppIdDevicePermissionFlags
-        get() = appIdDevicePermissionFlagsReference.get()
-
     val appIdAppOpModes: AppIdAppOpModes
         get() = appIdAppOpModesReference.get()
 
@@ -391,7 +375,6 @@
 class MutableUserState private constructor(
     packageVersionsReference: PackageVersionsReference,
     appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
-    appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
     appIdAppOpModesReference: AppIdAppOpModesReference,
     packageAppOpModesReference: PackageAppOpModesReference,
     defaultPermissionGrantFingerprint: String?,
@@ -399,7 +382,6 @@
 ) : UserState(
     packageVersionsReference,
     appIdPermissionFlagsReference,
-    appIdDevicePermissionFlagsReference,
     appIdAppOpModesReference,
     packageAppOpModesReference,
     defaultPermissionGrantFingerprint,
@@ -408,7 +390,6 @@
     constructor() : this(
         PackageVersionsReference(MutableIndexedMap<String, Int>()),
         AppIdPermissionFlagsReference(MutableAppIdPermissionFlags()),
-        AppIdDevicePermissionFlagsReference(MutableAppIdDevicePermissionFlags()),
         AppIdAppOpModesReference(MutableAppIdAppOpModes()),
         PackageAppOpModesReference(MutablePackageAppOpModes()),
         null,
@@ -418,7 +399,6 @@
     internal constructor(userState: UserState) : this(
         userState.packageVersionsReference.toImmutable(),
         userState.appIdPermissionFlagsReference.toImmutable(),
-        userState.appIdDevicePermissionFlagsReference.toImmutable(),
         userState.appIdAppOpModesReference.toImmutable(),
         userState.packageAppOpModesReference.toImmutable(),
         userState.defaultPermissionGrantFingerprint,
@@ -430,9 +410,6 @@
     fun mutateAppIdPermissionFlags(): MutableAppIdPermissionFlags =
         appIdPermissionFlagsReference.mutate()
 
-    fun mutateAppIdDevicePermissionFlags(): MutableAppIdDevicePermissionFlags =
-        appIdDevicePermissionFlagsReference.mutate()
-
     fun mutateAppIdAppOpModes(): MutableAppIdAppOpModes = appIdAppOpModesReference.mutate()
 
     fun mutatePackageAppOpModes(): MutablePackageAppOpModes = packageAppOpModesReference.mutate()
diff --git a/services/permission/java/com/android/server/permission/access/AccessUri.kt b/services/permission/java/com/android/server/permission/access/AccessUri.kt
index 1d46ca7..d1abc04 100644
--- a/services/permission/java/com/android/server/permission/access/AccessUri.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessUri.kt
@@ -65,17 +65,6 @@
     }
 }
 
-data class DevicePermissionUri(
-    val permissionName: String,
-    val deviceId: Int
-) : AccessUri(SCHEME) {
-    override fun toString(): String = "$scheme:///$permissionName/$deviceId"
-
-    companion object {
-        const val SCHEME = "device-permission"
-    }
-}
-
 data class UidUri(
     val uid: Int
 ) : AccessUri(SCHEME) {
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
deleted file mode 100644
index 37a4a90..0000000
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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.server.permission.access.permission
-
-import android.util.Slog
-import com.android.modules.utils.BinaryXmlPullParser
-import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.DevicePermissionFlags
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutableAppIdDevicePermissionFlags
-import com.android.server.permission.access.MutableDevicePermissionFlags
-import com.android.server.permission.access.WriteMode
-import com.android.server.permission.access.immutable.IndexedMap
-import com.android.server.permission.access.immutable.MutableIndexedMap
-import com.android.server.permission.access.immutable.forEachIndexed
-import com.android.server.permission.access.immutable.forEachReversedIndexed
-import com.android.server.permission.access.immutable.set
-import com.android.server.permission.access.util.andInv
-import com.android.server.permission.access.util.attributeInt
-import com.android.server.permission.access.util.attributeInterned
-import com.android.server.permission.access.util.forEachTag
-import com.android.server.permission.access.util.getAttributeIntOrThrow
-import com.android.server.permission.access.util.getAttributeValueOrThrow
-import com.android.server.permission.access.util.hasBits
-import com.android.server.permission.access.util.tag
-import com.android.server.permission.access.util.tagName
-
-class DevicePermissionPersistence {
-    fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
-        when (tagName) {
-            TAG_APP_ID_DEVICE_PERMISSIONS -> parseAppIdDevicePermissions(state, userId)
-            else -> {}
-        }
-    }
-
-    private fun BinaryXmlPullParser.parseAppIdDevicePermissions(
-        state: MutableAccessState,
-        userId: Int
-    ) {
-        val userState = state.mutateUserState(userId, WriteMode.NONE)!!
-        val appIdDevicePermissionFlags = userState.mutateAppIdDevicePermissionFlags()
-        forEachTag {
-            when (tagName) {
-                TAG_APP_ID -> parseAppId(appIdDevicePermissionFlags)
-                else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
-            }
-        }
-
-        appIdDevicePermissionFlags.forEachReversedIndexed { appIdIndex, appId, _ ->
-            if (appId !in state.externalState.appIdPackageNames) {
-                Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state")
-                appIdDevicePermissionFlags.removeAt(appIdIndex)
-                userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
-            }
-        }
-    }
-
-    private fun BinaryXmlPullParser.parseAppId(
-        appIdPermissionFlags: MutableAppIdDevicePermissionFlags
-    ) {
-        val appId = getAttributeIntOrThrow(ATTR_ID)
-        val devicePermissionFlags = MutableDevicePermissionFlags()
-        appIdPermissionFlags[appId] = devicePermissionFlags
-        forEachTag {
-            when (tagName) {
-                TAG_DEVICE -> parseDevice(devicePermissionFlags)
-                else -> {
-                    Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
-                }
-            }
-        }
-    }
-
-    private fun BinaryXmlPullParser.parseDevice(
-        deviceIdPermissionFlags: MutableDevicePermissionFlags
-    ) {
-        val deviceId = getAttributeValueOrThrow(ATTR_ID)
-        val permissionFlags = MutableIndexedMap<String, Int>()
-        deviceIdPermissionFlags.put(deviceId, permissionFlags)
-        forEachTag {
-            when (tagName) {
-                TAG_PERMISSION -> parsePermission(permissionFlags)
-                else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
-            }
-        }
-    }
-
-    private fun BinaryXmlPullParser.parsePermission(
-        permissionFlags: MutableIndexedMap<String, Int>
-    ) {
-        val name = getAttributeValueOrThrow(ATTR_NAME).intern()
-        val flags = getAttributeIntOrThrow(ATTR_FLAGS)
-        permissionFlags[name] = flags
-    }
-
-    fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
-        val appIdDevicePermissionFlags = state.userStates[userId]!!.appIdDevicePermissionFlags
-        tag(TAG_APP_ID_DEVICE_PERMISSIONS) {
-            appIdDevicePermissionFlags.forEachIndexed { _, appId, devicePermissionFlags ->
-                serializeAppId(appId, devicePermissionFlags)
-            }
-        }
-    }
-
-    private fun BinaryXmlSerializer.serializeAppId(
-        appId: Int,
-        devicePermissionFlags: DevicePermissionFlags
-    ) {
-        tag(TAG_APP_ID) {
-            attributeInt(ATTR_ID, appId)
-            devicePermissionFlags.forEachIndexed { _, deviceId, permissionFlags ->
-                serializeDevice(deviceId, permissionFlags)
-            }
-        }
-    }
-
-    private fun BinaryXmlSerializer.serializeDevice(
-        deviceId: String,
-        permissionFlags: IndexedMap<String, Int>
-    ) {
-        tag(TAG_DEVICE) {
-            attributeInterned(ATTR_ID, deviceId)
-            permissionFlags.forEachIndexed { _, name, flags ->
-                serializePermission(name, flags)
-            }
-        }
-    }
-
-    private fun BinaryXmlSerializer.serializePermission(name: String, flags: Int) {
-        tag(TAG_PERMISSION) {
-            attributeInterned(ATTR_NAME, name)
-            // Never serialize one-time permissions as granted.
-            val serializedFlags = if (flags.hasBits(PermissionFlags.ONE_TIME)) {
-                flags andInv PermissionFlags.RUNTIME_GRANTED
-            } else {
-                flags
-            }
-            attributeInt(ATTR_FLAGS, serializedFlags)
-        }
-    }
-
-    companion object {
-        private val LOG_TAG = DevicePermissionPersistence::class.java.simpleName
-
-        private const val TAG_APP_ID_DEVICE_PERMISSIONS = "app-id-device-permissions"
-        private const val TAG_APP_ID = "app-id"
-        private const val TAG_DEVICE = "device"
-        private const val TAG_PERMISSION = "permission"
-
-        private const val ATTR_ID = "id"
-        private const val ATTR_NAME = "name"
-        private const val ATTR_FLAGS = "flags"
-    }
-}
\ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
deleted file mode 100644
index c0d7546..0000000
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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.server.permission.access.permission
-
-import android.util.Slog
-import com.android.modules.utils.BinaryXmlPullParser
-import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.DevicePermissionUri
-import com.android.server.permission.access.GetStateScope
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutateStateScope
-import com.android.server.permission.access.SchemePolicy
-import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.util.andInv
-import com.android.server.pm.pkg.PackageState
-
-class DevicePermissionPolicy : SchemePolicy() {
-    private val persistence = DevicePermissionPersistence()
-
-    @Volatile
-    private var listeners: IndexedListSet<OnDevicePermissionFlagsChangedListener> =
-        MutableIndexedListSet()
-    private val listenersLock = Any()
-
-    override val subjectScheme: String
-        get() = UidUri.SCHEME
-
-    override val objectScheme: String
-        get() = DevicePermissionUri.SCHEME
-
-    override fun GetStateScope.onStateMutated() {
-        listeners.forEachIndexed { _, it -> it.onStateMutated() }
-    }
-
-    override fun MutateStateScope.onAppIdRemoved(appId: Int) {
-        newState.userStates.forEachIndexed { userStateIndex, _, userState ->
-            if (appId in userState.appIdDevicePermissionFlags) {
-                newState.mutateUserStateAt(userStateIndex)
-                    .mutateAppIdDevicePermissionFlags() -= appId
-            }
-        }
-    }
-
-    override fun MutateStateScope.onStorageVolumeMounted(
-        volumeUuid: String?,
-        packageNames: List<String>,
-        isSystemUpdated: Boolean
-    ) {
-        packageNames.forEachIndexed { _, packageName ->
-            val packageState = newState.externalState.packageStates[packageName]!!
-            trimPermissionStates(packageState.appId)
-        }
-    }
-
-    override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
-        trimPermissionStates(packageState.appId)
-    }
-
-    override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
-        if (appId in newState.externalState.appIdPackageNames) {
-            trimPermissionStates(appId)
-        }
-    }
-
-    override fun MutateStateScope.onPackageUninstalled(
-        packageName: String,
-        appId: Int,
-        userId: Int
-    ) {
-        resetPermissionStates(packageName, userId)
-    }
-
-    private fun MutateStateScope.resetPermissionStates(packageName: String, userId: Int) {
-        // It's okay to skip resetting permissions for packages that are removed,
-        // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
-        val packageState = newState.externalState.packageStates[packageName] ?: return
-        val androidPackage = packageState.androidPackage ?: return
-        val appId = packageState.appId
-        val appIdPermissionFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags
-        androidPackage.requestedPermissions.forEach { permissionName ->
-            val isRequestedByOtherPackages = anyPackageInAppId(appId) {
-                it.packageName != packageName &&
-                    permissionName in it.androidPackage!!.requestedPermissions
-            }
-            if (isRequestedByOtherPackages) {
-                return@forEach
-            }
-            appIdPermissionFlags[appId]?.forEachIndexed { _, deviceId, _ ->
-                setPermissionFlags(appId, deviceId, userId, permissionName, 0)
-            }
-        }
-    }
-
-    private fun MutateStateScope.trimPermissionStates(appId: Int) {
-        val requestedPermissions = MutableIndexedSet<String>()
-        forEachPackageInAppId(appId) {
-            requestedPermissions += it.androidPackage!!.requestedPermissions
-        }
-        newState.userStates.forEachIndexed { _, userId, userState ->
-            userState.appIdDevicePermissionFlags[appId]?.forEachReversedIndexed {
-                    _, deviceId, permissionFlags ->
-                permissionFlags.forEachReversedIndexed { _, permissionName, _ ->
-                    if (permissionName !in requestedPermissions) {
-                        setPermissionFlags(appId, deviceId, userId, permissionName, 0)
-                    }
-                }
-            }
-        }
-    }
-
-    private inline fun MutateStateScope.anyPackageInAppId(
-        appId: Int,
-        state: AccessState = newState,
-        predicate: (PackageState) -> Boolean
-    ): Boolean {
-        val packageNames = state.externalState.appIdPackageNames[appId]!!
-        return packageNames.anyIndexed { _, packageName ->
-            val packageState = state.externalState.packageStates[packageName]!!
-            packageState.androidPackage != null && predicate(packageState)
-        }
-    }
-
-    private inline fun MutateStateScope.forEachPackageInAppId(
-        appId: Int,
-        state: AccessState = newState,
-        action: (PackageState) -> Unit
-    ) {
-        val packageNames = state.externalState.appIdPackageNames[appId]!!
-        packageNames.forEachIndexed { _, packageName ->
-            val packageState = state.externalState.packageStates[packageName]!!
-            if (packageState.androidPackage != null) {
-                action(packageState)
-            }
-        }
-    }
-
-    override fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
-        with(persistence) { this@parseUserState.parseUserState(state, userId) }
-    }
-
-    override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
-        with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
-    }
-
-    fun GetStateScope.getPermissionFlags(
-        appId: Int,
-        deviceId: String,
-        userId: Int,
-        permissionName: String
-    ): Int =
-        state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId)
-            ?.getWithDefault(permissionName, 0) ?: 0
-
-    fun MutateStateScope.setPermissionFlags(
-        appId: Int,
-        deviceId: String,
-        userId: Int,
-        permissionName: String,
-        flags: Int
-    ): Boolean =
-        updatePermissionFlags(
-            appId, deviceId, userId, permissionName, PermissionFlags.MASK_ALL, flags
-        )
-
-    private fun MutateStateScope.updatePermissionFlags(
-        appId: Int,
-        deviceId: String,
-        userId: Int,
-        permissionName: String,
-        flagMask: Int,
-        flagValues: Int
-    ): Boolean {
-        if (!isDeviceAwarePermission(permissionName)) {
-            Slog.w(LOG_TAG, "$permissionName is not a device aware permission.")
-            return false
-        }
-        val oldFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags[appId]
-            ?.get(deviceId).getWithDefault(permissionName, 0)
-        val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
-        if (oldFlags == newFlags) {
-            return false
-        }
-        val appIdDevicePermissionFlags =
-            newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
-        val devicePermissionFlags = appIdDevicePermissionFlags.mutateOrPut(appId) {
-            MutableIndexedReferenceMap()
-        }
-        val permissionFlags = devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() }
-        permissionFlags.putWithDefault(permissionName, newFlags, 0)
-        if (permissionFlags.isEmpty()) {
-            devicePermissionFlags -= deviceId
-            if (devicePermissionFlags.isEmpty()) {
-                appIdDevicePermissionFlags -= appId
-            }
-        }
-        listeners.forEachIndexed { _, it ->
-            it.onDevicePermissionFlagsChanged(
-                appId, userId, deviceId, permissionName, oldFlags, newFlags
-            )
-        }
-        return true
-    }
-
-    fun addOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
-        synchronized(listenersLock) {
-            listeners = listeners + listener
-        }
-    }
-
-    fun removeOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
-        synchronized(listenersLock) {
-            listeners = listeners - listener
-        }
-    }
-
-    private fun isDeviceAwarePermission(permissionName: String): Boolean =
-        DEVICE_SUPPORTED_PERMISSIONS.contains(permissionName)
-
-    companion object {
-        private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName
-
-        /**
-         * These permissions are supported for virtual devices.
-         */
-        private val DEVICE_SUPPORTED_PERMISSIONS = indexedSetOf(
-            android.Manifest.permission.CAMERA,
-            android.Manifest.permission.RECORD_AUDIO
-        )
-    }
-
-    /**
-     * TODO: b/289355341 - implement listener for permission changes
-     * Listener for permission flags changes.
-     */
-    abstract class OnDevicePermissionFlagsChangedListener {
-        /**
-         * Called when a permission flags change has been made to the upcoming new state.
-         *
-         * Implementations should keep this method fast to avoid stalling the locked state mutation,
-         * and only call external code after [onStateMutated] when the new state has actually become
-         * the current state visible to external code.
-         */
-        abstract fun onDevicePermissionFlagsChanged(
-            appId: Int,
-            userId: Int,
-            deviceId: String,
-            permissionName: String,
-            oldFlags: Int,
-            newFlags: Int
-        )
-
-        /**
-         * Called when the upcoming new state has become the current state.
-         *
-         * Implementations should keep this method fast to avoid stalling the locked state mutation.
-         */
-        abstract fun onStateMutated()
-    }
-}
\ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index f0705ed..b797492 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -64,11 +64,9 @@
 import com.android.server.PermissionThread
 import com.android.server.ServiceThread
 import com.android.server.SystemConfig
-import com.android.server.companion.virtual.VirtualDeviceManagerInternal
 import com.android.server.permission.access.AccessCheckingService
 import com.android.server.permission.access.AccessState
 import com.android.server.permission.access.AppOpUri
-import com.android.server.permission.access.DevicePermissionUri
 import com.android.server.permission.access.GetStateScope
 import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.PermissionUri
@@ -112,9 +110,6 @@
     private val policy =
         service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
 
-    private val devicePolicy =
-        service.getSchemePolicy(UidUri.SCHEME, DevicePermissionUri.SCHEME) as DevicePermissionPolicy
-
     private val context = service.context
     private lateinit var metricsLogger: MetricsLogger
     private lateinit var packageManagerInternal: PackageManagerInternal
@@ -135,8 +130,6 @@
     @GuardedBy("storageVolumeLock")
     private val storageVolumePackageNames = ArrayMap<String?, MutableList<String>>()
 
-    private var virtualDeviceManagerInternal: VirtualDeviceManagerInternal? = null
-
     private lateinit var permissionControllerManager: PermissionControllerManager
 
     /**
@@ -159,6 +152,7 @@
         systemConfig = SystemConfig.getInstance()
         userManagerInternal = LocalServices.getService(UserManagerInternal::class.java)
         userManagerService = UserManagerService.getInstance()
+
         // The package info cache is the cache for package and permission information.
         // Disable the package info and package permission caches locally but leave the
         // checkPermission cache active.
@@ -466,7 +460,7 @@
         return size
     }
 
-    override fun checkUidPermission(uid: Int, permissionName: String, deviceId: Int): Int {
+    override fun checkUidPermission(uid: Int, permissionName: String): Int {
         val userId = UserHandle.getUserId(uid)
         if (!userManagerInternal.exists(userId)) {
             return PackageManager.PERMISSION_DENIED
@@ -488,7 +482,7 @@
                 return PackageManager.PERMISSION_DENIED
             }
             val isPermissionGranted = service.getState {
-                isPermissionGranted(packageState, userId, permissionName, deviceId)
+                isPermissionGranted(packageState, userId, permissionName)
             }
             return if (isPermissionGranted) {
                 PackageManager.PERMISSION_GRANTED
@@ -521,12 +515,7 @@
         return false
     }
 
-    override fun checkPermission(
-        packageName: String,
-        permissionName: String,
-        deviceId: Int,
-        userId: Int
-    ): Int {
+    override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
         if (!userManagerInternal.exists(userId)) {
             return PackageManager.PERMISSION_DENIED
         }
@@ -535,7 +524,7 @@
             .use { it.getPackageState(packageName) } ?: return PackageManager.PERMISSION_DENIED
 
         val isPermissionGranted = service.getState {
-            isPermissionGranted(packageState, userId, permissionName, deviceId)
+            isPermissionGranted(packageState, userId, permissionName)
         }
         return if (isPermissionGranted) {
             PackageManager.PERMISSION_GRANTED
@@ -553,21 +542,19 @@
     private fun GetStateScope.isPermissionGranted(
         packageState: PackageState,
         userId: Int,
-        permissionName: String,
-        deviceId: Int
+        permissionName: String
     ): Boolean {
         val appId = packageState.appId
         // Note that instant apps can't have shared UIDs, so we only need to check the current
         // package state.
         val isInstantApp = packageState.getUserStateOrDefault(userId).isInstantApp
-        if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName, deviceId)) {
+        if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName)) {
             return true
         }
 
         val fullerPermissionName = FULLER_PERMISSIONS[permissionName]
         if (fullerPermissionName != null &&
-            isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName, deviceId)
-        ) {
+            isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName)) {
             return true
         }
 
@@ -581,10 +568,9 @@
         appId: Int,
         userId: Int,
         isInstantApp: Boolean,
-        permissionName: String,
-        deviceId: Int,
+        permissionName: String
     ): Boolean {
-        val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+        val flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
         if (!PermissionFlags.isPermissionGranted(flags)) {
             return false
         }
@@ -615,8 +601,7 @@
                 ?: return emptySet()
 
             return permissionFlags.mapNotNullIndexedTo(ArraySet()) { _, permissionName, _ ->
-                if (isPermissionGranted(
-                        packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT)) {
+                if (isPermissionGranted(packageState, userId, permissionName)) {
                     permissionName
                 } else {
                     null
@@ -655,26 +640,18 @@
         }
     }
 
-    override fun grantRuntimePermission(
-        packageName: String,
-        permissionName: String,
-        deviceId: Int,
-        userId: Int
-    ) {
-        setRuntimePermissionGranted(
-            packageName, userId, permissionName, deviceId, isGranted = true
-        )
+    override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
+        setRuntimePermissionGranted(packageName, userId, permissionName, isGranted = true)
     }
 
     override fun revokeRuntimePermission(
         packageName: String,
         permissionName: String,
-        deviceId: Int,
         userId: Int,
         reason: String?
     ) {
         setRuntimePermissionGranted(
-            packageName, userId, permissionName, deviceId, isGranted = false, revokeReason = reason
+            packageName, userId, permissionName, isGranted = false, revokeReason = reason
         )
     }
 
@@ -683,8 +660,8 @@
         userId: Int
     ) {
         setRuntimePermissionGranted(
-            packageName, userId, Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT,
-            isGranted = false, skipKillUid = true
+            packageName, userId, Manifest.permission.POST_NOTIFICATIONS, isGranted = false,
+            skipKillUid = true
         )
     }
 
@@ -696,7 +673,6 @@
         packageName: String,
         userId: Int,
         permissionName: String,
-        deviceId: Int,
         isGranted: Boolean,
         skipKillUid: Boolean = false,
         revokeReason: String? = null
@@ -772,7 +748,7 @@
             }
 
             setRuntimePermissionGranted(
-                packageState, userId, permissionName, deviceId, isGranted, canManageRolePermission,
+                packageState, userId, permissionName, isGranted, canManageRolePermission,
                 overridePolicyFixed, reportError = true, methodName
             )
         }
@@ -806,16 +782,14 @@
                         if (permissionState ==
                             PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
                             setRuntimePermissionGranted(
-                                packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT,
-                                isGranted = true, canManageRolePermission = false,
-                                overridePolicyFixed = false, reportError = false,
-                                "setRequestedPermissionStates"
+                                packageState, userId, permissionName, isGranted = true,
+                                canManageRolePermission = false, overridePolicyFixed = false,
+                                reportError = false, "setRequestedPermissionStates"
                             )
                             updatePermissionFlags(
                                 packageState.appId, userId, permissionName,
-                                Context.DEVICE_ID_DEFAULT,
                                 PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED or
-                                PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
+                                    PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
                                 canUpdateSystemFlags = false,
                                 reportErrorForUnknownPermission = false,
                                 isPermissionRequested = true, "setRequestedPermissionStates",
@@ -842,7 +816,6 @@
         packageState: PackageState,
         userId: Int,
         permissionName: String,
-        deviceId: Int,
         isGranted: Boolean,
         canManageRolePermission: Boolean,
         overridePolicyFixed: Boolean,
@@ -898,7 +871,7 @@
         }
 
         val appId = packageState.appId
-        val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+        val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
 
         if (permissionName !in androidPackage.requestedPermissions && oldFlags == 0) {
             if (reportError) {
@@ -961,7 +934,7 @@
             return
         }
 
-        setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
+        with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
 
         if (permission.isRuntime) {
             val action = if (isGranted) {
@@ -990,12 +963,7 @@
         with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
     }
 
-    override fun getPermissionFlags(
-        packageName: String,
-        permissionName: String,
-        deviceId: Int,
-        userId: Int,
-    ): Int {
+    override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
         if (!userManagerInternal.exists(userId)) {
             Slog.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
             return 0
@@ -1026,8 +994,7 @@
             }
 
             val flags =
-                getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
-
+                with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
             return PermissionFlags.toApiFlags(flags)
         }
     }
@@ -1035,7 +1002,6 @@
     override fun isPermissionRevokedByPolicy(
         packageName: String,
         permissionName: String,
-        deviceId: Int,
         userId: Int
     ): Boolean {
         if (!userManagerInternal.exists(userId)) {
@@ -1052,13 +1018,13 @@
             .use { it.getPackageState(packageName) } ?: return false
 
         service.getState {
-            if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
+            if (isPermissionGranted(packageState, userId, permissionName)) {
                 return false
             }
 
-            val flags =
-                getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
-
+            val flags = with(policy) {
+                getPermissionFlags(packageState.appId, userId, permissionName)
+            }
             return flags.hasBits(PermissionFlags.POLICY_FIXED)
         }
     }
@@ -1080,8 +1046,7 @@
     override fun shouldShowRequestPermissionRationale(
         packageName: String,
         permissionName: String,
-        deviceId: Int,
-        userId: Int,
+        userId: Int
     ): Boolean {
         if (!userManagerInternal.exists(userId)) {
             Slog.w(LOG_TAG, "shouldShowRequestPermissionRationale: Unknown user $userId")
@@ -1103,11 +1068,11 @@
 
         val flags: Int
         service.getState {
-            if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
+            if (isPermissionGranted(packageState, userId, permissionName)) {
                 return false
             }
 
-            flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+            flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
         }
         if (flags.hasAnyBit(UNREQUESTABLE_MASK)) {
             return false
@@ -1139,7 +1104,6 @@
         flagMask: Int,
         flagValues: Int,
         enforceAdjustPolicyPermission: Boolean,
-        deviceId: Int,
         userId: Int
     ) {
         val callingUid = Binder.getCallingUid()
@@ -1235,7 +1199,7 @@
         val appId = packageState.appId
         service.mutateState {
             updatePermissionFlags(
-                appId, userId, permissionName, deviceId, flagMask, flagValues, canUpdateSystemFlags,
+                appId, userId, permissionName, flagMask, flagValues, canUpdateSystemFlags,
                 reportErrorForUnknownPermission = true, isPermissionRequested,
                 "updatePermissionFlags", packageName
             )
@@ -1284,9 +1248,8 @@
                 val androidPackage = packageState.androidPackage ?: return@forEach
                 androidPackage.requestedPermissions.forEach { permissionName ->
                     updatePermissionFlags(
-                        packageState.appId, userId, permissionName, Context.DEVICE_ID_DEFAULT,
-                        flagMask, flagValues, canUpdateSystemFlags,
-                        reportErrorForUnknownPermission = false,
+                        packageState.appId, userId, permissionName, flagMask, flagValues,
+                        canUpdateSystemFlags, reportErrorForUnknownPermission = false,
                         isPermissionRequested = true, "updatePermissionFlagsForAllApps", packageName
                     )
                 }
@@ -1301,7 +1264,6 @@
         appId: Int,
         userId: Int,
         permissionName: String,
-        deviceId: Int,
         flagMask: Int,
         flagValues: Int,
         canUpdateSystemFlags: Boolean,
@@ -1336,7 +1298,7 @@
             return
         }
 
-        val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+        val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
         if (!isPermissionRequested && oldFlags == 0) {
             Slog.w(
                 LOG_TAG, "$methodName: Permission $permissionName isn't requested by package" +
@@ -1346,7 +1308,7 @@
         }
 
         val newFlags = PermissionFlags.updateFlags(permission, oldFlags, flagMask, flagValues)
-        setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
+        with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
     }
 
     override fun getAllowlistedRestrictedPermissions(
@@ -1403,63 +1365,6 @@
         )
     }
 
-    private fun GetStateScope.getPermissionFlagsWithPolicy(
-        appId: Int,
-        userId: Int,
-        permissionName: String,
-        deviceId: Int,
-    ): Int {
-        return if (deviceId == Context.DEVICE_ID_DEFAULT) {
-            with(policy) { getPermissionFlags(appId, userId, permissionName) }
-        } else {
-            val virtualDeviceManagerInternal = virtualDeviceManagerInternal
-            if (virtualDeviceManagerInternal == null) {
-                Slog.e(LOG_TAG, "Virtual device manager service is not available.")
-                return 0
-            }
-            val persistentDeviceId =
-                    virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
-            if (persistentDeviceId != null) {
-                with(devicePolicy) {
-                    getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
-                }
-            } else {
-                Slog.e(LOG_TAG, "Invalid device ID $deviceId.")
-                0
-            }
-        }
-    }
-
-    private fun MutateStateScope.setPermissionFlagsWithPolicy(
-        appId: Int,
-        userId: Int,
-        permissionName: String,
-        deviceId: Int,
-        flags: Int
-    ): Boolean {
-        return if (deviceId == Context.DEVICE_ID_DEFAULT) {
-            with(policy) {
-               setPermissionFlags(appId, userId, permissionName, flags)
-            }
-        } else {
-            val virtualDeviceManagerInternal = virtualDeviceManagerInternal
-            if (virtualDeviceManagerInternal == null) {
-                Slog.e(LOG_TAG, "Virtual device manager service is not available.")
-                return false
-            }
-            val persistentDeviceId =
-                    virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
-            if (persistentDeviceId != null) {
-                with(devicePolicy) {
-                    setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
-                }
-            } else {
-                Slog.e(LOG_TAG, "Invalid device ID $deviceId.")
-                false
-            }
-        }
-    }
-
     /**
      * This method does not enforce checks on the caller, should only be called after
      * required checks.
@@ -1634,7 +1539,8 @@
     ) {
         service.mutateState {
             with(policy) {
-                val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState
+                val permissionsFlags =
+                    getUidPermissionFlags(appId, userId) ?: return@mutateState
 
                 val permissions = getPermissions()
                 androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission ->
@@ -1755,6 +1661,8 @@
         )
     }
 
+
+
     override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
         requireNotNull(permissionName) { "permissionName cannot be null" }
         val packageNames = ArraySet<String>()
@@ -1971,7 +1879,7 @@
                     println("Permissions:")
                     withIndent {
                         userState.appIdPermissionFlags[appId]?.forEachIndexed {
-                            _, permissionName, flags ->
+                                _, permissionName, flags ->
                             val isGranted = PermissionFlags.isPermissionGranted(flags)
                             println(
                                 "$permissionName: granted=$isGranted, flags=" +
@@ -1980,20 +1888,6 @@
                         }
                     }
 
-                    userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
-                            _, deviceId, devicePermissionFlags ->
-                        println("Permissions (Device $deviceId):")
-                        withIndent {
-                            devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
-                                val isGranted = PermissionFlags.isPermissionGranted(flags)
-                                println(
-                                    "$permissionName: granted=$isGranted, flags=" +
-                                        PermissionFlags.toString(flags)
-                                )
-                            }
-                        }
-                    }
-
                     println("App ops:")
                     withIndent {
                         userState.appIdAppOpModes[appId]?.forEachIndexed {_, appOpName, appOpMode ->
@@ -2109,8 +2003,6 @@
 
     override fun onSystemReady() {
         service.onSystemReady()
-        virtualDeviceManagerInternal =
-                LocalServices.getService(VirtualDeviceManagerInternal::class.java)
         permissionControllerManager = PermissionControllerManager(
             context, PermissionThread.getHandler()
         )
@@ -2520,7 +2412,7 @@
         }
 
         private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
-            if (checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
+            if (checkUidPermission(uid, Manifest.permission.BACKUP) !=
                 PackageManager.PERMISSION_GRANTED) {
                 return false
             }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 76e6ec7..8e01a11 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -32,8 +32,10 @@
 import static org.mockito.Mockito.anyFloat;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -390,6 +392,35 @@
         assertEquals(Float.POSITIVE_INFINITY, hbmc.getHdrBrightnessValue(), 0.0);
     }
 
+    @Test
+    public void testHdrRespectsChangingDesiredHdrSdrRatio() {
+        final Runnable hbmChangedCallback = mock(Runnable.class);
+        final HighBrightnessModeController hbmc = new TestHbmBuilder()
+                .setClock(new OffsettableClock())
+                .setHdrBrightnessConfig(mHdrBrightnessDeviceConfigMock)
+                .setHbmChangedCallback(hbmChangedCallback)
+                .build();
+
+        // Passthrough return the max desired hdr/sdr ratio
+        when(mHdrBrightnessDeviceConfigMock.getHdrBrightnessFromSdr(anyFloat(), anyFloat()))
+                .thenAnswer(i -> i.getArgument(1));
+
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 2.0f /*maxDesiredHdrSdrRatio*/);
+        advanceTime(0);
+        assertEquals(2.0f, hbmc.getHdrBrightnessValue(), EPSILON);
+        verify(hbmChangedCallback, times(1)).run();
+
+        // Verify that a change in only the desired hdrSdrRatio still results in the changed
+        // callback being invoked
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/,
+                3.0f /*maxDesiredHdrSdrRatio*/);
+        advanceTime(0);
+        assertEquals(3.0f, hbmc.getHdrBrightnessValue(), 0.0);
+        verify(hbmChangedCallback, times(2)).run();
+    }
+
 
     @Test
     public void testHdrTrumpsSunlight() {
@@ -698,6 +729,7 @@
     private class TestHbmBuilder {
         OffsettableClock mClock;
         HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessCfg;
+        Runnable mHdrChangedCallback = () -> {};
 
         TestHbmBuilder setClock(OffsettableClock clock) {
             mClock = clock;
@@ -711,6 +743,11 @@
             return this;
         }
 
+        TestHbmBuilder setHbmChangedCallback(Runnable runnable) {
+            mHdrChangedCallback = runnable;
+            return this;
+        }
+
         HighBrightnessModeController build() {
             initHandler(mClock);
             if (mHighBrightnessModeMetadata == null) {
@@ -718,8 +755,8 @@
             }
             return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
                     DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
-                    DEFAULT_HBM_DATA, mHdrBrightnessCfg, () -> {}, mHighBrightnessModeMetadata,
-                    mContextSpy);
+                    DEFAULT_HBM_DATA, mHdrBrightnessCfg, mHdrChangedCallback,
+                    mHighBrightnessModeMetadata, mContextSpy);
         }
 
     }
diff --git a/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
index d3c0e35..8e328ca 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
@@ -191,7 +191,17 @@
 
         mTestPolicyFile = new File(mContextSpy.getCacheDir(), "lps_policy.xml");
         mController = new LowPowerStandbyController(mContextSpy, mTestLooper.getLooper(),
-                () -> mClock.now(), mDeviceConfigWrapperMock, () -> mIActivityManagerMock,
+                new LowPowerStandbyController.Clock() {
+                    @Override
+                    public long elapsedRealtime() {
+                        return mClock.now();
+                    }
+
+                    @Override
+                    public long uptimeMillis() {
+                        return mClock.now();
+                    }
+                }, mDeviceConfigWrapperMock, () -> mIActivityManagerMock,
                 mTestPolicyFile);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index bb20244..b44d52e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -296,7 +296,7 @@
                 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW).build();
         final ActivityRecord activity1 = new ActivityBuilder(mAtm)
                 .setTask(task1).setUid(ActivityBuilder.DEFAULT_FAKE_UID + 1).build();
-        task1.setResumedActivity(activity1, "test");
+        activity1.setState(ActivityRecord.State.RESUMED, "test");
 
         final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
                 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index f332b69..1dd71e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1093,10 +1093,16 @@
         final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         // Add an extra activity on top of the root one.
-        new ActivityBuilder(mAtm).setTask(task).build();
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
                 task.getBottomMostActivity(), task.getRootActivity());
+        assertEquals("The task id of root activity must be reported.",
+                task.mTaskId, mAtm.mActivityClientController.getTaskForActivity(
+                        activity0.token, true /* onlyRoot */));
+        assertEquals("No task must be reported for non root activity if onlyRoot.",
+                INVALID_TASK_ID, mAtm.mActivityClientController.getTaskForActivity(
+                        activity1.token, true /* onlyRoot */));
     }
 
     /**
@@ -1572,8 +1578,7 @@
     }
 
     private Task getTestTask() {
-        final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
-        return task.getBottomMostTask();
+        return new TaskBuilder(mSupervisor).setCreateActivity(true).build();
     }
 
     private void testRootTaskBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e738d29..90b798c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2061,6 +2061,15 @@
             return mode == AppOpsManager.MODE_ALLOWED;
         }
 
+        private boolean canReportUsageStats() {
+            if (isCallingUidSystem()) {
+                return true; // System UID can always report UsageStats
+            }
+
+            return getContext().checkCallingPermission(Manifest.permission.REPORT_USAGE_STATS)
+                    == PackageManager.PERMISSION_GRANTED;
+        }
+
         private boolean hasObserverPermission() {
             final int callingUid = Binder.getCallingUid();
             DevicePolicyManagerInternal dpmInternal = getDpmInternal();
@@ -2541,14 +2550,19 @@
         @Override
         public void reportChooserSelection(@NonNull String packageName, int userId,
                 @NonNull String contentType, String[] annotations, @NonNull String action) {
-            if (packageName == null) {
-                throw new IllegalArgumentException("Package selection must not be null.");
-            }
-            // A valid contentType and action must be provided for chooser selection events.
-            if (contentType == null || contentType.isBlank()
-                    || action == null || action.isBlank()) {
+            // A valid package name, content type, and action must be provided for these events
+            Objects.requireNonNull(packageName);
+            Objects.requireNonNull(contentType);
+            Objects.requireNonNull(action);
+            if (contentType.isBlank() || action.isBlank()) {
                 return;
             }
+
+            if (!canReportUsageStats()) {
+                throw new SecurityException("Only the system or holders of the REPORT_USAGE_STATS"
+                        + " permission are allowed to call reportChooserSelection");
+            }
+
             // Verify if this package exists before reporting an event for it.
             if (mPackageManagerInternal.getPackageUid(packageName, 0, userId) < 0) {
                 Slog.w(TAG, "Event report user selecting an invalid package");
@@ -2566,9 +2580,11 @@
         @Override
         public void reportUserInteraction(String packageName, int userId) {
             Objects.requireNonNull(packageName);
-            if (!isCallingUidSystem()) {
-                throw new SecurityException("Only system is allowed to call reportUserInteraction");
+            if (!canReportUsageStats()) {
+                throw new SecurityException("Only the system or holders of the REPORT_USAGE_STATS"
+                        + " permission are allowed to call reportUserInteraction");
             }
+
             final Event event = new Event(USER_INTERACTION, SystemClock.elapsedRealtime());
             event.mPackage = packageName;
             reportEventOrAddToQueue(userId, event);