Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit caa1bd17 authored by Matt Pietal's avatar Matt Pietal
Browse files

Take #2: Shutoff calls to KeyguardStatusViewController

This will help extraneous code from running, as well as ensure
the new viewmodels are fully in control.

As part of this, make sure everything reuses the same burn-in logic
across keyguard. Also make sure that we will never adjust things
into the top offset, and log if a bad calculation is determined.

Take #2: This fixes a bad use of stateIn and optimizes use of
burnIn, to only calculate once instead of 3 times

Fixes: 327351128
Fixes: 325921793
Test: atest AodBurnInViewModelTest KeyguardIndicationAreaViewModelTest
Flag: ACONFIG com.android.systemui.migrate_clocks_to_blueprint
TEAMFOOD

Change-Id: Iac8576108c0213bca4f5b4f184690cd1219e5834
parent 8bf9e5e1
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import androidx.compose.ui.layout.onPlaced
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel
import kotlinx.coroutines.flow.map

/**
 * Modifies the composable to account for anti-burn in translation, alpha, and scaling.
@@ -38,9 +39,18 @@ fun Modifier.burnInAware(
    params: BurnInParameters,
    isClock: Boolean = false,
): Modifier {
    val translationX by viewModel.translationX(params).collectAsState(initial = 0f)
    val translationY by viewModel.translationY(params).collectAsState(initial = 0f)
    val scaleViewModel by viewModel.scale(params).collectAsState(initial = BurnInScaleViewModel())
    val burnIn = viewModel.movement(params)
    val translationX by burnIn.map { it.translationX.toFloat() }.collectAsState(initial = 0f)
    val translationY by burnIn.map { it.translationY.toFloat() }.collectAsState(initial = 0f)
    val scaleViewModel by
        burnIn
            .map {
                BurnInScaleViewModel(
                    scale = it.scale,
                    scaleClockOnly = it.scaleClockOnly,
                )
            }
            .collectAsState(initial = BurnInScaleViewModel())

    return this.graphicsLayer {
        val scale =
+0 −19
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
import com.android.systemui.common.shared.model.Position
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback
@@ -151,24 +150,6 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
            assertThat(underTest.topClippingBounds.value).isEqualTo(500)
        }

    @Test
    fun clockPosition() =
        testScope.runTest {
            assertThat(underTest.clockPosition.value).isEqualTo(Position(0, 0))

            underTest.setClockPosition(0, 1)
            assertThat(underTest.clockPosition.value).isEqualTo(Position(0, 1))

            underTest.setClockPosition(1, 9)
            assertThat(underTest.clockPosition.value).isEqualTo(Position(1, 9))

            underTest.setClockPosition(1, 0)
            assertThat(underTest.clockPosition.value).isEqualTo(Position(1, 0))

            underTest.setClockPosition(3, 1)
            assertThat(underTest.clockPosition.value).isEqualTo(Position(3, 1))
        }

    @Test
    fun dozeTimeTick() =
        testScope.runTest {
+43 −85
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ class AodBurnInViewModelTest : SysuiTestCase() {
        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)

        MockitoAnnotations.initMocks(this)
        whenever(burnInInteractor.keyguardBurnIn).thenReturn(burnInFlow)
        whenever(burnInInteractor.burnIn(anyInt(), anyInt())).thenReturn(burnInFlow)
        kosmos.burnInInteractor = burnInInteractor
        whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt()))
            .thenReturn(emptyFlow())
@@ -81,18 +81,18 @@ class AodBurnInViewModelTest : SysuiTestCase() {
    }

    @Test
    fun translationY_initializedToZero() =
    fun movement_initializedToZero() =
        testScope.runTest {
            val translationY by collectLastValue(underTest.translationY(burnInParameters))
            assertThat(translationY).isEqualTo(0)
            val movement by collectLastValue(underTest.movement(burnInParameters))
            assertThat(movement?.translationY).isEqualTo(0)
            assertThat(movement?.translationX).isEqualTo(0)
            assertThat(movement?.scale).isEqualTo(0f)
        }

    @Test
    fun translationAndScale_whenNotDozing() =
        testScope.runTest {
            val translationX by collectLastValue(underTest.translationX(burnInParameters))
            val translationY by collectLastValue(underTest.translationY(burnInParameters))
            val scale by collectLastValue(underTest.scale(burnInParameters))
            val movement by collectLastValue(underTest.movement(burnInParameters))

            // Set to not dozing (on lockscreen)
            keyguardTransitionRepository.sendTransitionStep(
@@ -113,24 +113,17 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    scale = 0.5f,
                )

            assertThat(translationX).isEqualTo(0)
            assertThat(translationY).isEqualTo(0)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 1f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationX).isEqualTo(0)
            assertThat(movement?.translationY).isEqualTo(0)
            assertThat(movement?.scale).isEqualTo(1f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)
        }

    @Test
    fun translationAndScale_whenFullyDozing() =
        testScope.runTest {
            burnInParameters = burnInParameters.copy(minViewY = 100)
            val translationX by collectLastValue(underTest.translationX(burnInParameters))
            val translationY by collectLastValue(underTest.translationY(burnInParameters))
            val scale by collectLastValue(underTest.scale(burnInParameters))
            val movement by collectLastValue(underTest.movement(burnInParameters))

            // Set to dozing (on AOD)
            keyguardTransitionRepository.sendTransitionStep(
@@ -150,15 +143,10 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    scale = 0.5f,
                )

            assertThat(translationX).isEqualTo(20)
            assertThat(translationY).isEqualTo(30)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 0.5f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationX).isEqualTo(20)
            assertThat(movement?.translationY).isEqualTo(30)
            assertThat(movement?.scale).isEqualTo(0.5f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)

            // Set to the beginning of GONE->AOD transition
            keyguardTransitionRepository.sendTransitionStep(
@@ -170,15 +158,10 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                ),
                validateStep = false,
            )
            assertThat(translationX).isEqualTo(0)
            assertThat(translationY).isEqualTo(0)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 1f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationX).isEqualTo(0)
            assertThat(movement?.translationY).isEqualTo(0)
            assertThat(movement?.scale).isEqualTo(1f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)
        }

    @Test
@@ -191,9 +174,7 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    minViewY = 100,
                    topInset = 80,
                )
            val translationX by collectLastValue(underTest.translationX(burnInParameters))
            val translationY by collectLastValue(underTest.translationY(burnInParameters))
            val scale by collectLastValue(underTest.scale(burnInParameters))
            val movement by collectLastValue(underTest.movement(burnInParameters))

            // Set to dozing (on AOD)
            keyguardTransitionRepository.sendTransitionStep(
@@ -213,16 +194,11 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    translationY = -30,
                    scale = 0.5f,
                )
            assertThat(translationX).isEqualTo(20)
            assertThat(movement?.translationX).isEqualTo(20)
            // -20 instead of -30, due to inset of 80
            assertThat(translationY).isEqualTo(-20)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 0.5f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationY).isEqualTo(-20)
            assertThat(movement?.scale).isEqualTo(0.5f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)

            // Set to the beginning of GONE->AOD transition
            keyguardTransitionRepository.sendTransitionStep(
@@ -234,15 +210,10 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                ),
                validateStep = false,
            )
            assertThat(translationX).isEqualTo(0)
            assertThat(translationY).isEqualTo(0)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 1f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationX).isEqualTo(0)
            assertThat(movement?.translationY).isEqualTo(0)
            assertThat(movement?.scale).isEqualTo(1f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)
        }

    @Test
@@ -255,9 +226,7 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    minViewY = 100,
                    topInset = 80,
                )
            val translationX by collectLastValue(underTest.translationX(burnInParameters))
            val translationY by collectLastValue(underTest.translationY(burnInParameters))
            val scale by collectLastValue(underTest.scale(burnInParameters))
            val movement by collectLastValue(underTest.movement(burnInParameters))

            // Set to dozing (on AOD)
            keyguardTransitionRepository.sendTransitionStep(
@@ -277,16 +246,11 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    translationY = -30,
                    scale = 0.5f,
                )
            assertThat(translationX).isEqualTo(20)
            assertThat(movement?.translationX).isEqualTo(20)
            // -20 instead of -30, due to inset of 80
            assertThat(translationY).isEqualTo(-20)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 0.5f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationY).isEqualTo(-20)
            assertThat(movement?.scale).isEqualTo(0.5f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)

            // Set to the beginning of GONE->AOD transition
            keyguardTransitionRepository.sendTransitionStep(
@@ -298,15 +262,10 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                ),
                validateStep = false,
            )
            assertThat(translationX).isEqualTo(0)
            assertThat(translationY).isEqualTo(0)
            assertThat(scale)
                .isEqualTo(
                    BurnInScaleViewModel(
                        scale = 1f,
                        scaleClockOnly = true,
                    )
                )
            assertThat(movement?.translationX).isEqualTo(0)
            assertThat(movement?.translationY).isEqualTo(0)
            assertThat(movement?.scale).isEqualTo(1f)
            assertThat(movement?.scaleClockOnly).isEqualTo(true)
        }

    @Test
@@ -314,9 +273,7 @@ class AodBurnInViewModelTest : SysuiTestCase() {
        testScope.runTest {
            whenever(clockController.config.useAlternateSmartspaceAODTransition).thenReturn(true)

            val translationX by collectLastValue(underTest.translationX(burnInParameters))
            val translationY by collectLastValue(underTest.translationY(burnInParameters))
            val scale by collectLastValue(underTest.scale(burnInParameters))
            val movement by collectLastValue(underTest.movement(burnInParameters))

            // Set to dozing (on AOD)
            keyguardTransitionRepository.sendTransitionStep(
@@ -337,8 +294,9 @@ class AodBurnInViewModelTest : SysuiTestCase() {
                    scale = 0.5f,
                )

            assertThat(translationX).isEqualTo(0)
            assertThat(translationY).isEqualTo(0)
            assertThat(scale).isEqualTo(BurnInScaleViewModel(scale = 0.5f, scaleClockOnly = false))
            assertThat(movement?.translationX).isEqualTo(0)
            assertThat(movement?.translationY).isEqualTo(0)
            assertThat(movement?.scale).isEqualTo(0.5f)
            assertThat(movement?.scaleClockOnly).isEqualTo(false)
        }
}
+77 −58
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@

package com.android.systemui.keyguard.ui.viewmodel

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
@@ -24,9 +25,13 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -36,18 +41,23 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(JUnit4::class)
@RunWith(AndroidJUnit4::class)
class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    @Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
    @Mock private lateinit var shortcutsCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel

    @Mock private lateinit var burnInInteractor: BurnInInteractor
    private val burnInFlow = MutableStateFlow(BurnInModel())

    private lateinit var bottomAreaInteractor: KeyguardBottomAreaInteractor
    private lateinit var underTest: KeyguardIndicationAreaViewModel
    private lateinit var repository: FakeKeyguardRepository

@@ -70,9 +80,11 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
        MockitoAnnotations.initMocks(this)

        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)

        whenever(burnInHelperWrapper.burnInOffset(anyInt(), any()))
            .thenReturn(RETURNED_BURN_IN_OFFSET)
        whenever(burnInInteractor.burnIn(anyInt(), anyInt())).thenReturn(burnInFlow)

        val withDeps = KeyguardInteractorFactory.create()
        val keyguardInteractor = withDeps.keyguardInteractor
@@ -82,19 +94,22 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
        whenever(bottomAreaViewModel.startButton).thenReturn(startButtonFlow)
        whenever(bottomAreaViewModel.endButton).thenReturn(endButtonFlow)
        whenever(bottomAreaViewModel.alpha).thenReturn(alphaFlow)
        bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository)
        underTest =
            KeyguardIndicationAreaViewModel(
                keyguardInteractor = keyguardInteractor,
                bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
                bottomAreaInteractor = bottomAreaInteractor,
                keyguardBottomAreaViewModel = bottomAreaViewModel,
                burnInHelperWrapper = burnInHelperWrapper,
                burnInInteractor = burnInInteractor,
                shortcutsCombinedViewModel = shortcutsCombinedViewModel,
                configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()),
            )
    }

    @Test
    fun alpha() = runTest {
    fun alpha() =
        testScope.runTest {
            val value = collectLastValue(underTest.alpha)

            assertThat(value()).isEqualTo(1f)
@@ -109,7 +124,8 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
        }

    @Test
    fun isIndicationAreaPadded() = runTest {
    fun isIndicationAreaPadded() =
        testScope.runTest {
            repository.setKeyguardShowing(true)
            val value = collectLastValue(underTest.isIndicationAreaPadded)

@@ -125,23 +141,26 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() {
        }

    @Test
    fun indicationAreaTranslationX() = runTest {
    fun indicationAreaTranslationX() =
        testScope.runTest {
            val value = collectLastValue(underTest.indicationAreaTranslationX)

            assertThat(value()).isEqualTo(0f)
        repository.setClockPosition(100, 100)
            bottomAreaInteractor.setClockPosition(100, 100)
            assertThat(value()).isEqualTo(100f)
        repository.setClockPosition(200, 100)
            bottomAreaInteractor.setClockPosition(200, 100)
            assertThat(value()).isEqualTo(200f)
        repository.setClockPosition(200, 200)
            bottomAreaInteractor.setClockPosition(200, 200)
            assertThat(value()).isEqualTo(200f)
        repository.setClockPosition(300, 100)
            bottomAreaInteractor.setClockPosition(300, 100)
            assertThat(value()).isEqualTo(300f)
        }

    @Test
    fun indicationAreaTranslationY() = runTest {
        val value = collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET))
    fun indicationAreaTranslationY() =
        testScope.runTest {
            val value =
                collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET))

            // Negative 0 - apparently there's a difference in floating point arithmetic - FML
            assertThat(value()).isEqualTo(-0f)
+5 −4
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic
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.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -66,7 +67,7 @@ import org.mockito.Mockito.mock
@RunWith(AndroidJUnit4::class)
class SharedNotificationContainerViewModelTest : SysuiTestCase() {
    val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)
    lateinit var translationYFlow: MutableStateFlow<Float>
    lateinit var movementFlow: MutableStateFlow<BurnInModel>

    val kosmos =
        testKosmos().apply {
@@ -95,8 +96,8 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
    @Before
    fun setUp() {
        overrideResource(R.bool.config_use_split_notification_shade, false)
        translationYFlow = MutableStateFlow(0f)
        whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow)
        movementFlow = MutableStateFlow(BurnInModel())
        whenever(aodBurnInViewModel.movement(any())).thenReturn(movementFlow)
        underTest = kosmos.sharedNotificationContainerViewModel
    }

@@ -608,7 +609,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
            showLockscreen()
            assertThat(translationY).isEqualTo(0)

            translationYFlow.value = 150f
            movementFlow.value = BurnInModel(translationY = 150)
            assertThat(translationY).isEqualTo(150f)
        }

Loading