Merge "Change burn in preventing mechanism for clock" into main
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index c109e51..abbf0ea 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -58,15 +58,11 @@
             .collectAsState(initial = BurnInScaleViewModel())
 
     return this.graphicsLayer {
-        val scale =
-            when {
-                scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale
-                else -> 1f
-            }
-
         this.translationX = if (isClock) 0F else translationX
         this.translationY = translationY
         this.alpha = alpha
+
+        val scale = if (scaleViewModel.scaleClockOnly) scaleViewModel.scale else 1f
         this.scaleX = scale
         this.scaleY = scale
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index e270d9e..519bb6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -62,8 +62,8 @@
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val keyguardClockRepository = kosmos.fakeKeyguardClockRepository
     private lateinit var underTest: AodBurnInViewModel
-
-    private var burnInParameters = BurnInParameters()
+    // assign a smaller value to minViewY to avoid overflow
+    private var burnInParameters = BurnInParameters(minViewY = Int.MAX_VALUE / 2)
     private val burnInFlow = MutableStateFlow(BurnInModel())
 
     @Before
@@ -296,52 +296,111 @@
                     scale = 0.5f,
                 )
 
-            assertThat(movement?.translationX).isEqualTo(0)
-            assertThat(movement?.translationY).isEqualTo(0)
+            assertThat(movement?.translationX).isEqualTo(20)
+            assertThat(movement?.translationY).isEqualTo(30)
             assertThat(movement?.scale).isEqualTo(0.5f)
             assertThat(movement?.scaleClockOnly).isEqualTo(false)
         }
 
     @Test
-    fun translationAndScale_composeFlagOn_weatherLargeClock() =
-        testBurnInViewModelWhenComposeFlagOn(
+    fun translationAndScale_composeFlagOff_weatherLargeClock() =
+        testBurnInViewModelForClocks(
             isSmallClock = false,
             isWeatherClock = true,
-            expectedScaleOnly = false
+            expectedScaleOnly = false,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = false
+        )
+
+    @Test
+    fun translationAndScale_composeFlagOff_weatherSmallClock() =
+        testBurnInViewModelForClocks(
+            isSmallClock = true,
+            isWeatherClock = true,
+            expectedScaleOnly = false,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = false
+        )
+
+    @Test
+    fun translationAndScale_composeFlagOff_nonWeatherLargeClock() =
+        testBurnInViewModelForClocks(
+            isSmallClock = false,
+            isWeatherClock = false,
+            expectedScaleOnly = true,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = false
+        )
+
+    @Test
+    fun translationAndScale_composeFlagOff_nonWeatherSmallClock() =
+        testBurnInViewModelForClocks(
+            isSmallClock = true,
+            isWeatherClock = false,
+            expectedScaleOnly = false,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = false
+        )
+
+    @Test
+    fun translationAndScale_composeFlagOn_weatherLargeClock() =
+        testBurnInViewModelForClocks(
+            isSmallClock = false,
+            isWeatherClock = true,
+            expectedScaleOnly = false,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = true
         )
 
     @Test
     fun translationAndScale_composeFlagOn_weatherSmallClock() =
-        testBurnInViewModelWhenComposeFlagOn(
+        testBurnInViewModelForClocks(
             isSmallClock = true,
             isWeatherClock = true,
-            expectedScaleOnly = true
+            expectedScaleOnly = false,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = true
         )
 
     @Test
     fun translationAndScale_composeFlagOn_nonWeatherLargeClock() =
-        testBurnInViewModelWhenComposeFlagOn(
+        testBurnInViewModelForClocks(
             isSmallClock = false,
             isWeatherClock = false,
-            expectedScaleOnly = true
+            expectedScaleOnly = true,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = true
         )
 
     @Test
     fun translationAndScale_composeFlagOn_nonWeatherSmallClock() =
-        testBurnInViewModelWhenComposeFlagOn(
+        testBurnInViewModelForClocks(
             isSmallClock = true,
             isWeatherClock = false,
-            expectedScaleOnly = true
+            expectedScaleOnly = false,
+            enableMigrateClocksToBlueprintFlag = true,
+            enableComposeLockscreenFlag = true
         )
 
-    private fun testBurnInViewModelWhenComposeFlagOn(
+    private fun testBurnInViewModelForClocks(
         isSmallClock: Boolean,
         isWeatherClock: Boolean,
-        expectedScaleOnly: Boolean
+        expectedScaleOnly: Boolean,
+        enableMigrateClocksToBlueprintFlag: Boolean,
+        enableComposeLockscreenFlag: Boolean
     ) =
         testScope.runTest {
-            mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
-            mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+            if (enableMigrateClocksToBlueprintFlag) {
+                mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+            } else {
+                mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+            }
+
+            if (enableComposeLockscreenFlag) {
+                mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+            } else {
+                mSetFlagsRule.disableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+            }
             if (isSmallClock) {
                 keyguardClockRepository.setClockSize(ClockSize.SMALL)
                 // we need the following step to update stateFlow value
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 79bf5f1..629c96c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -109,6 +109,12 @@
     val largeClockMessageBuffer: MessageBuffer,
 )
 
+data class AodClockBurnInModel(
+    val scale: Float,
+    val translationX: Float,
+    val translationY: Float,
+)
+
 /** Specifies layout information for the */
 interface ClockFaceLayout {
     /** All clock views to add to the root constraint layout before applying constraints. */
@@ -118,6 +124,8 @@
     fun applyConstraints(constraints: ConstraintSet): ConstraintSet
 
     fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet
+
+    fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
 }
 
 /** A ClockFaceLayout that applies the default lockscreen layout to a single view */
@@ -137,6 +145,10 @@
     override fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet {
         return constraints
     }
+
+    override fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) {
+        // Default clock doesn't need detailed control of view
+    }
 }
 
 /** Events that should call when various rendering parameters change */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index ed5d53c..c846cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -33,14 +33,18 @@
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
 import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.clocks.AodClockBurnInModel
 import com.android.systemui.plugins.clocks.ClockController
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.launch
 
 object KeyguardClockViewBinder {
     private val TAG = KeyguardClockViewBinder::class.simpleName!!
     // When changing to new clock, we need to remove old clock views from burnInLayer
     private var lastClock: ClockController? = null
+
     @JvmStatic
     fun bind(
         clockSection: ClockSection,
@@ -48,6 +52,7 @@
         viewModel: KeyguardClockViewModel,
         keyguardClockInteractor: KeyguardClockInteractor,
         blueprintInteractor: KeyguardBlueprintInteractor,
+        rootViewModel: KeyguardRootViewModel,
     ) {
         keyguardRootView.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.CREATED) {
@@ -105,6 +110,28 @@
                         }
                     }
                 }
+
+                launch {
+                    if (!MigrateClocksToBlueprint.isEnabled) return@launch
+                    combine(
+                            rootViewModel.translationX,
+                            rootViewModel.translationY,
+                            rootViewModel.scale,
+                            ::Triple
+                        )
+                        .collect { (translationX, translationY, scale) ->
+                            viewModel.currentClock.value
+                                ?.largeClock
+                                ?.layout
+                                ?.applyAodBurnIn(
+                                    AodClockBurnInModel(
+                                        translationX = translationX.value!!,
+                                        translationY = translationY,
+                                        scale = scale.scale
+                                    )
+                                )
+                        }
+                }
             }
         }
     }
@@ -117,17 +144,16 @@
     ) {
         val burnInLayer = viewModel.burnInLayer
         val clockController = viewModel.currentClock.value
+        // Large clocks won't be added to or removed from burn in layer
+        // Weather large clock has customized burn in preventing mechanism
+        // Non-weather large clock will only scale and translate vertically
         clockController?.let { clock ->
             when (clockSize) {
                 ClockSize.LARGE -> {
                     clock.smallClock.layout.views.forEach { burnInLayer?.removeView(it) }
-                    if (clock.config.useAlternateSmartspaceAODTransition) {
-                        clock.largeClock.layout.views.forEach { burnInLayer?.addView(it) }
-                    }
                 }
                 ClockSize.SMALL -> {
                     clock.smallClock.layout.views.forEach { burnInLayer?.addView(it) }
-                    clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) }
                 }
             }
         }
@@ -148,13 +174,6 @@
                 burnInLayer?.removeView(it)
                 rootView.removeView(it)
             }
-
-            // add large clock to burn in layer only when it will have same transition with other
-            // components in AOD otherwise, it will have a separate scale transition while other
-            // components only have translate transition
-            if (clock.config.useAlternateSmartspaceAODTransition) {
-                clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) }
-            }
             clock.largeClock.layout.views.forEach { rootView.removeView(it) }
         }
         lastClock = currentClock
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 4451bca..39db22d 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
@@ -257,23 +257,6 @@
                                         it.scaleX = scaleViewModel.scale
                                         it.scaleY = scaleViewModel.scale
                                     }
-                                    // Make sure to reset these views, or they will be invisible
-                                    if (childViews[burnInLayerId]?.scaleX != 1f) {
-                                        childViews[burnInLayerId]?.scaleX = 1f
-                                        childViews[burnInLayerId]?.scaleY = 1f
-                                        childViews[aodNotificationIconContainerId]?.scaleX = 1f
-                                        childViews[aodNotificationIconContainerId]?.scaleY = 1f
-                                        view.requestLayout()
-                                    }
-                                } else {
-                                    // For weather clock, large clock should have only scale
-                                    // transition with other parts in burnInLayer
-                                    childViews[burnInLayerId]?.scaleX = scaleViewModel.scale
-                                    childViews[burnInLayerId]?.scaleY = scaleViewModel.scale
-                                    childViews[aodNotificationIconContainerId]?.scaleX =
-                                        scaleViewModel.scale
-                                    childViews[aodNotificationIconContainerId]?.scaleY =
-                                        scaleViewModel.scale
                                 }
                             }
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index ef29270..b367715 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockFaceLayout
@@ -64,6 +65,7 @@
     private val context: Context,
     val smartspaceViewModel: KeyguardSmartspaceViewModel,
     val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
+    private val rootViewModel: KeyguardRootViewModel,
 ) : KeyguardSection() {
     override fun addViews(constraintLayout: ConstraintLayout) {}
     override fun bindData(constraintLayout: ConstraintLayout) {
@@ -75,7 +77,8 @@
             constraintLayout,
             keyguardClockViewModel,
             clockInteractor,
-            blueprintInteractor.get()
+            blueprintInteractor.get(),
+            rootViewModel,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 5b83a10..c05a1b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -27,7 +27,6 @@
 import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.ComposeLockscreen
 import com.android.systemui.keyguard.shared.model.BurnInModel
 import com.android.systemui.keyguard.shared.model.ClockSize
 import com.android.systemui.keyguard.ui.StateToValue
@@ -121,11 +120,13 @@
             ),
         ) { interpolated, burnIn ->
             val useAltAod =
-                keyguardClockViewModel.currentClock.value?.let { clock ->
-                    clock.config.useAlternateSmartspaceAODTransition
-                } == true
+                keyguardClockViewModel.currentClock.value
+                    ?.config
+                    ?.useAlternateSmartspaceAODTransition == true
+            // Only scale large non-weather clocks
+            // elements in large weather clock will translate the same as smartspace
             val useScaleOnly =
-                useAltAod && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
+                (!useAltAod) && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
 
             val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt()
             val translationY =
@@ -134,35 +135,12 @@
                 } else {
                     max(params.topInset, params.minViewY + burnInY) - params.minViewY
                 }
-            if (ComposeLockscreen.isEnabled) {
-                BurnInModel(
-                    translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
-                    translationY = translationY,
-                    scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
-                    scaleClockOnly = !useScaleOnly,
-                )
-            } else {
-                if (useScaleOnly) {
-                    BurnInModel(
-                        translationX = 0,
-                        translationY = 0,
-                        scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
-                    )
-                } else {
-                    // Ensure the desired translation doesn't encroach on the top inset
-                    BurnInModel(
-                        translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
-                        translationY = translationY,
-                        scale =
-                            MathUtils.lerp(
-                                /* start= */ burnIn.scale,
-                                /* stop= */ 1f,
-                                /* amount= */ 1f - interpolated,
-                            ),
-                        scaleClockOnly = true,
-                    )
-                }
-            }
+            BurnInModel(
+                translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
+                translationY = translationY,
+                scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
+                scaleClockOnly = useScaleOnly
+            )
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
index 2f650c4..040d3b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
@@ -85,7 +85,6 @@
         setupWeatherClock()
         KeyguardClockViewBinder.updateBurnInLayer(rootView, clockViewModel, ClockSize.LARGE)
         verify(burnInLayer).removeView(smallClockView)
-        verify(burnInLayer).addView(largeClockView)
     }
 
     @Test
@@ -101,7 +100,6 @@
         setupNonWeatherClock()
         KeyguardClockViewBinder.updateBurnInLayer(rootView, clockViewModel, ClockSize.SMALL)
         verify(burnInLayer).addView(smallClockView)
-        verify(burnInLayer).removeView(largeClockView)
     }
 
     private fun setupWeatherClock() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
index ba2efe6..b3cc5c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor
 import com.android.systemui.keyguard.shared.model.ClockSize
 import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
 import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
@@ -117,6 +118,7 @@
                     context,
                     keyguardSmartspaceViewModel,
                     { keyguardBlueprintInteractor },
+                    keyguardRootViewModel,
                 )
         }
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
index 90a93f4..a6b40df 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
 import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel
+import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel
 import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.util.mockito.mock
@@ -37,6 +38,7 @@
             context = applicationContext,
             smartspaceViewModel = keyguardSmartspaceViewModel,
             blueprintInteractor = { keyguardBlueprintInteractor },
+            rootViewModel = keyguardRootViewModel,
         )
     }