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
index b2bc06f0ae29722ccbf0dec09be7ce97769d7f61..48d374207388eadd6aac4566a5dbd7ce39849709 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
@@ -20,4 +20,7 @@ package com.android.systemui.common.shared.model
 data class SharedNotificationContainerPosition(
     val top: Float = 0f,
     val bottom: Float = 0f,
+
+    /** Whether any modifications to top/bottom are smoothly animated */
+    val animate: Boolean = false,
 )
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 4d5c503d1c4e719e41d11a9c38c4a33933a422fb..67a12b06de0f55e862dd6885d1d59921d79b9ccc 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
@@ -22,6 +22,8 @@ import android.view.View
 import android.view.View.OnLayoutChangeListener
 import android.view.ViewGroup
 import android.view.ViewGroup.OnHierarchyChangeListener
+import android.view.WindowInsets
+import android.view.WindowInsets.Type
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.internal.jank.InteractionJankMonitor
@@ -242,11 +244,18 @@ object KeyguardRootViewBinder {
             }
         )
 
+        view.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets ->
+            val insetTypes = WindowInsets.Type.systemBars() or WindowInsets.Type.displayCutout()
+            viewModel.topInset = insets.getInsetsIgnoringVisibility(insetTypes).top
+            insets
+        }
+
         return object : DisposableHandle {
             override fun dispose() {
                 disposableHandle.dispose()
                 view.removeOnLayoutChangeListener(onLayoutChangeListener)
                 view.setOnHierarchyChangeListener(null)
+                view.setOnApplyWindowInsetsListener(null)
                 childViews.clear()
             }
         }
@@ -288,7 +297,6 @@ object KeyguardRootViewBinder {
             oldBottom: Int
         ) {
             val nsslPlaceholder = v.findViewById(R.id.nssl_placeholder) as View?
-
             if (nsslPlaceholder != null) {
                 // After layout, ensure the notifications are positioned correctly
                 viewModel.onSharedNotificationContainerPositionChanged(
@@ -296,6 +304,11 @@ object KeyguardRootViewBinder {
                     nsslPlaceholder.bottom.toFloat(),
                 )
             }
+
+            val ksv = v.findViewById(R.id.keyguard_status_view) as View?
+            if (ksv != null) {
+                viewModel.statusViewTop = ksv.top
+            }
         }
     }
 
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 1f98082c406513a7225b26db425e6543fdf90ece..e12da53287ed9c58f74519173250d6b3b5f839bb 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
@@ -65,7 +65,12 @@ constructor(
      */
     private val previewMode = MutableStateFlow(PreviewMode())
 
-    public var clockControllerProvider: Provider<ClockController>? = null
+    var clockControllerProvider: Provider<ClockController>? = null
+
+    /** System insets that keyguard needs to stay out of */
+    var topInset: Int = 0
+    /** Status view top, without translation added in */
+    var statusViewTop: Int = 0
 
     val burnInLayerVisibility: Flow<Int> =
         keyguardTransitionInteractor.startedKeyguardState
@@ -102,9 +107,12 @@ constructor(
                     scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolation),
                 )
             } else {
+                // Ensure the desired translation doesn't encroach on the top inset
+                val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolation).toInt()
+                val translationY = -(statusViewTop - Math.max(topInset, statusViewTop + burnInY))
                 BurnInModel(
                     translationX = MathUtils.lerp(0, burnIn.translationX, interpolation).toInt(),
-                    translationY = MathUtils.lerp(0, burnIn.translationY, interpolation).toInt(),
+                    translationY = translationY,
                     scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolation),
                     scaleClockOnly = true,
                 )
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 2af7181f2f31d6558e6a020fc5a36695993b5296..6785da4bf4f15710c4d430e287606195dda87903 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
@@ -59,10 +59,8 @@ object SharedNotificationContainerBinder {
 
                 launch {
                     viewModel.position.collect {
-                        controller.updateTopPadding(
-                            it.top,
-                            controller.isAddOrRemoveAnimationPending()
-                        )
+                        val animate = it.animate || controller.isAddOrRemoveAnimationPending()
+                        controller.updateTopPadding(it.top, animate)
                     }
                 }
 
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 1229cb9b49acab4a9ccfe469256e79c0464e3079..b86b5dcc7939d578a938f62ad831550f4fca32be 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
@@ -25,6 +25,7 @@ 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 com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -118,8 +119,15 @@ constructor(
                     }
                 }
             } else {
-                interactor.topPosition.map { top ->
-                    keyguardInteractor.sharedNotificationContainerPosition.value.copy(top = top)
+                interactor.topPosition.sample(shadeInteractor.qsExpansion, ::Pair).map {
+                    (top, qsExpansion) ->
+                    // When QS expansion > 0, it should directly set the top padding so do not
+                    // animate it
+                    val animate = qsExpansion == 0f
+                    keyguardInteractor.sharedNotificationContainerPosition.value.copy(
+                        top = top,
+                        animate = animate
+                    )
                 }
             }
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 4f545cb0e288ce44b4d952a43bb138c96c0f6d30..b80771ff646c72501b8e5ddffbe621a06348fad7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -179,6 +179,8 @@ class KeyguardRootViewModelTest : SysuiTestCase() {
             val translationY by collectLastValue(underTest.translationY)
             val scale by collectLastValue(underTest.scale)
 
+            underTest.statusViewTop = 100
+
             // Set to dozing (on AOD)
             dozeAmountTransitionStep.emit(TransitionStep(value = 1f))
             // Trigger a change to the burn-in model
@@ -199,6 +201,37 @@ class KeyguardRootViewModelTest : SysuiTestCase() {
             assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */))
         }
 
+    @Test
+    fun translationAndScaleFromBurnFullyDozingStaysOutOfTopInset() =
+        testScope.runTest {
+            val translationX by collectLastValue(underTest.translationX)
+            val translationY by collectLastValue(underTest.translationY)
+            val scale by collectLastValue(underTest.scale)
+
+            underTest.statusViewTop = 100
+            underTest.topInset = 80
+
+            // Set to dozing (on AOD)
+            dozeAmountTransitionStep.emit(TransitionStep(value = 1f))
+            // Trigger a change to the burn-in model
+            burnInFlow.value =
+                BurnInModel(
+                    translationX = 20,
+                    translationY = -30,
+                    scale = 0.5f,
+                )
+            assertThat(translationX).isEqualTo(20)
+            // -20 instead of -30, due to inset of 80
+            assertThat(translationY).isEqualTo(-20)
+            assertThat(scale).isEqualTo(Pair(0.5f, true /* scaleClockOnly */))
+
+            // Set to the beginning of GONE->AOD transition
+            goneToAodTransitionStep.emit(TransitionStep(value = 0f))
+            assertThat(translationX).isEqualTo(0)
+            assertThat(translationY).isEqualTo(0)
+            assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */))
+        }
+
     @Test
     fun translationAndScaleFromBurnInUseScaleOnly() =
         testScope.runTest {
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 60421c981e6d7da80dcdbf1c39ca3bf87047c3bc..3a9d111bacf7b0707bc7b1a299dc7b6f7e526972 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
@@ -314,7 +314,26 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
             sharedNotificationContainerInteractor.setTopPosition(10f)
 
             assertThat(position)
-                .isEqualTo(SharedNotificationContainerPosition(top = 10f, bottom = 0f))
+                .isEqualTo(
+                    SharedNotificationContainerPosition(top = 10f, bottom = 0f, animate = true)
+                )
+        }
+
+    @Test
+    fun positionOnQS() =
+        testScope.runTest {
+            val position by collectLastValue(underTest.position)
+
+            // Start on lockscreen with shade expanded
+            showLockscreenWithQSExpanded()
+
+            // When not in split shade
+            sharedNotificationContainerInteractor.setTopPosition(10f)
+
+            assertThat(position)
+                .isEqualTo(
+                    SharedNotificationContainerPosition(top = 10f, bottom = 0f, animate = false)
+                )
         }
 
     @Test
@@ -390,6 +409,17 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
         )
     }
 
+    private suspend fun TestScope.showLockscreenWithQSExpanded() {
+        shadeRepository.setLockscreenShadeExpansion(0f)
+        shadeRepository.setQsExpansion(1f)
+        keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+        keyguardTransitionRepository.sendTransitionSteps(
+            from = KeyguardState.AOD,
+            to = KeyguardState.LOCKSCREEN,
+            this,
+        )
+    }
+
     @SysUISingleton
     @Component(
         modules =