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

Commit 09311d9d authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fade out UDFPS on shadeExpand & dialogProgress" into udc-qpr-dev

parents 410e1d09 15f23551
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -21,10 +21,16 @@ import android.animation.FloatEvaluator
import android.animation.IntEvaluator
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.hideAffordancesRequest
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart

/** Encapsulates business logic for transitions between UDFPS states on the keyguard. */
@ExperimentalCoroutinesApi
@@ -35,6 +41,8 @@ constructor(
    configRepo: ConfigurationRepository,
    burnInInteractor: BurnInInteractor,
    keyguardInteractor: KeyguardInteractor,
    shadeRepository: ShadeRepository,
    dialogManager: SystemUIDialogManager,
) {
    private val intEvaluator = IntEvaluator()
    private val floatEvaluator = FloatEvaluator()
@@ -56,6 +64,26 @@ constructor(
                floatEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInProgress),
            )
        }

    val dialogHideAffordancesRequest: Flow<Boolean> = dialogManager.hideAffordancesRequest

    val qsProgress: Flow<Float> =
        shadeRepository.qsExpansion // swipe from top of LS
            .map { (it * 2).coerceIn(0f, 1f) }
            .onStart { emit(0f) }

    val shadeExpansion: Flow<Float> =
        combine(
                shadeRepository.udfpsTransitionToFullShadeProgress, // swipe from middle of LS
                keyguardInteractor.statusBarState, // quick swipe from middle of LS
            ) { shadeProgress, statusBarState ->
                if (statusBarState == StatusBarState.SHADE_LOCKED) {
                    1f
                } else {
                    shadeProgress
                }
            }
            .onStart { emit(0f) }
}

data class BurnInOffsets(
+92 −36
Original line number Diff line number Diff line
@@ -21,13 +21,17 @@ import androidx.annotation.ColorInt
import com.android.settingslib.Utils.getColorAttrDefaultColor
import com.android.systemui.R
import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge

@@ -38,6 +42,8 @@ open class UdfpsLockscreenViewModel(
    lockscreenColorResId: Int,
    alternateBouncerColorResId: Int,
    transitionInteractor: KeyguardTransitionInteractor,
    udfpsKeyguardInteractor: UdfpsKeyguardInteractor,
    keyguardInteractor: KeyguardInteractor,
) {
    private val toLockscreen: Flow<TransitionViewModel> =
        transitionInteractor.anyStateToLockscreenTransition.map {
@@ -54,11 +60,12 @@ open class UdfpsLockscreenViewModel(
        }

    private val toAlternateBouncer: Flow<TransitionViewModel> =
        keyguardInteractor.statusBarState.flatMapLatest { statusBarState ->
            transitionInteractor.anyStateToAlternateBouncerTransition.map {
                TransitionViewModel(
                    alpha = 1f,
                    scale =
                    if (visibleInKeyguardState(it.from)) {
                        if (visibleInKeyguardState(it.from, statusBarState)) {
                            1f
                        } else {
                            it.value
@@ -66,8 +73,10 @@ open class UdfpsLockscreenViewModel(
                    color = getColorAttrDefaultColor(context, alternateBouncerColorResId),
                )
            }
        }

    private val fadeOut: Flow<TransitionViewModel> =
        keyguardInteractor.statusBarState.flatMapLatest { statusBarState ->
            merge(
                    transitionInteractor.anyStateToGoneTransition,
                    transitionInteractor.anyStateToAodTransition,
@@ -78,7 +87,7 @@ open class UdfpsLockscreenViewModel(
                .map {
                    TransitionViewModel(
                        alpha =
                        if (visibleInKeyguardState(it.from)) {
                            if (visibleInKeyguardState(it.from, statusBarState)) {
                                1f - it.value
                            } else {
                                0f
@@ -92,8 +101,12 @@ open class UdfpsLockscreenViewModel(
                            },
                    )
                }
        }

    private fun visibleInKeyguardState(state: KeyguardState): Boolean {
    private fun visibleInKeyguardState(
        state: KeyguardState,
        statusBarState: StatusBarState
    ): Boolean {
        return when (state) {
            KeyguardState.OFF,
            KeyguardState.DOZING,
@@ -102,17 +115,53 @@ open class UdfpsLockscreenViewModel(
            KeyguardState.PRIMARY_BOUNCER,
            KeyguardState.GONE,
            KeyguardState.OCCLUDED -> false
            KeyguardState.LOCKSCREEN,
            KeyguardState.LOCKSCREEN -> statusBarState == StatusBarState.KEYGUARD
            KeyguardState.ALTERNATE_BOUNCER -> true
        }
    }

    val transition: Flow<TransitionViewModel> =
    private val keyguardStateTransition =
        merge(
            toAlternateBouncer,
            toLockscreen,
            fadeOut,
        )

    private val dialogHideAffordancesAlphaMultiplier: Flow<Float> =
        udfpsKeyguardInteractor.dialogHideAffordancesRequest.map { hideAffordances ->
            if (hideAffordances) {
                0f
            } else {
                1f
            }
        }

    private val alphaMultiplier: Flow<Float> =
        combine(
            transitionInteractor.startedKeyguardState,
            dialogHideAffordancesAlphaMultiplier,
            udfpsKeyguardInteractor.shadeExpansion,
            udfpsKeyguardInteractor.qsProgress,
        ) { startedKeyguardState, dialogHideAffordancesAlphaMultiplier, shadeExpansion, qsProgress
            ->
            if (startedKeyguardState == KeyguardState.ALTERNATE_BOUNCER) {
                1f
            } else {
                dialogHideAffordancesAlphaMultiplier * (1f - shadeExpansion) * (1f - qsProgress)
            }
        }

    val transition: Flow<TransitionViewModel> =
        combine(
            alphaMultiplier,
            keyguardStateTransition,
        ) { alphaMultiplier, keyguardStateTransition ->
            TransitionViewModel(
                alpha = keyguardStateTransition.alpha * alphaMultiplier,
                scale = keyguardStateTransition.scale,
                color = keyguardStateTransition.color,
            )
        }
    val visible: Flow<Boolean> = transition.map { it.alpha != 0f }
}

@@ -123,12 +172,15 @@ constructor(
    val context: Context,
    transitionInteractor: KeyguardTransitionInteractor,
    interactor: UdfpsKeyguardInteractor,
    keyguardInteractor: KeyguardInteractor,
) :
    UdfpsLockscreenViewModel(
        context,
        android.R.attr.textColorPrimary,
        com.android.internal.R.attr.materialColorOnPrimaryFixed,
        transitionInteractor,
        interactor,
        keyguardInteractor,
    ) {
    val dozeAmount: Flow<Float> = interactor.dozeAmount
    val burnInOffsets: Flow<BurnInOffsets> = interactor.burnInOffsets
@@ -147,12 +199,16 @@ class BackgroundViewModel
constructor(
    val context: Context,
    transitionInteractor: KeyguardTransitionInteractor,
    interactor: UdfpsKeyguardInteractor,
    keyguardInteractor: KeyguardInteractor,
) :
    UdfpsLockscreenViewModel(
        context,
        com.android.internal.R.attr.colorSurface,
        com.android.internal.R.attr.materialColorPrimaryFixed,
        transitionInteractor,
        interactor,
        keyguardInteractor,
    )

data class TransitionViewModel(
+34 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow

/** Whether dialogs are requesting for affordances to be hidden or not. */
val SystemUIDialogManager.hideAffordancesRequest: Flow<Boolean>
    get() = conflatedCallbackFlow {
        val callback =
            SystemUIDialogManager.Listener { hideAffordance ->
                trySendWithFailureLogging(hideAffordance, "dialogHideAffordancesRequest")
            }
        registerListener(callback)
        trySendWithFailureLogging(shouldHideAffordance(), "dialogHideAffordancesRequestInitial")
        awaitClose { unregisterListener(callback) }
    }
+64 −1
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
@@ -46,6 +49,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@ExperimentalCoroutinesApi
@@ -63,19 +67,21 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
    private lateinit var fakeCommandQueue: FakeCommandQueue
    private lateinit var featureFlags: FakeFeatureFlags
    private lateinit var burnInInteractor: BurnInInteractor
    private lateinit var shadeRepository: FakeShadeRepository

    @Mock private lateinit var burnInHelper: BurnInHelperWrapper
    @Mock private lateinit var dialogManager: SystemUIDialogManager

    private lateinit var underTest: UdfpsKeyguardInteractor

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        testScope = TestScope()
        configRepository = FakeConfigurationRepository()
        keyguardRepository = FakeKeyguardRepository()
        bouncerRepository = FakeKeyguardBouncerRepository()
        shadeRepository = FakeShadeRepository()
        fakeCommandQueue = FakeCommandQueue()
        featureFlags =
            FakeFeatureFlags().apply {
@@ -102,6 +108,8 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
                    bouncerRepository,
                    configRepository,
                ),
                shadeRepository,
                dialogManager,
            )
    }

@@ -142,6 +150,61 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() {
            assertThat(burnInOffsets?.burnInXOffset).isEqualTo(burnInXOffset)
        }

    @Test
    fun dialogHideAffordances() =
        testScope.runTest {
            val dialogHideAffordancesRequest by
                collectLastValue(underTest.dialogHideAffordancesRequest)
            runCurrent()
            val captor = argumentCaptor<SystemUIDialogManager.Listener>()
            verify(dialogManager).registerListener(captor.capture())

            captor.value.shouldHideAffordances(false)
            assertThat(dialogHideAffordancesRequest).isEqualTo(false)

            captor.value.shouldHideAffordances(true)
            assertThat(dialogHideAffordancesRequest).isEqualTo(true)

            captor.value.shouldHideAffordances(false)
            assertThat(dialogHideAffordancesRequest).isEqualTo(false)
        }

    @Test
    fun shadeExpansion_updates() =
        testScope.runTest {
            keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
            val shadeExpansion by collectLastValue(underTest.shadeExpansion)
            assertThat(shadeExpansion).isEqualTo(0f)

            shadeRepository.setUdfpsTransitionToFullShadeProgress(.5f)
            assertThat(shadeExpansion).isEqualTo(.5f)

            shadeRepository.setUdfpsTransitionToFullShadeProgress(.7f)
            assertThat(shadeExpansion).isEqualTo(.7f)

            shadeRepository.setUdfpsTransitionToFullShadeProgress(.22f)
            assertThat(shadeExpansion).isEqualTo(.22f)

            keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
            assertThat(shadeExpansion).isEqualTo(1f)
        }

    @Test
    fun qsProgress_updates() =
        testScope.runTest {
            val qsProgress by collectLastValue(underTest.qsProgress)
            assertThat(qsProgress).isEqualTo(0f)

            shadeRepository.setQsExpansion(.22f)
            assertThat(qsProgress).isEqualTo(.44f)

            shadeRepository.setQsExpansion(.5f)
            assertThat(qsProgress).isEqualTo(1f)

            shadeRepository.setQsExpansion(.7f)
            assertThat(qsProgress).isEqualTo(1f)
        }

    private fun initializeBurnInOffsets() {
        whenever(burnInHelper.burnInProgressOffset()).thenReturn(burnInProgress)
        whenever(burnInHelper.burnInOffset(anyInt(), /* xAxis */ eq(true)))
+7 −0
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -58,7 +60,9 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
    private lateinit var keyguardRepository: FakeKeyguardRepository
    private lateinit var fakeCommandQueue: FakeCommandQueue
    private lateinit var featureFlags: FakeFeatureFlags
    private lateinit var shadeRepository: FakeShadeRepository

    @Mock private lateinit var dialogManager: SystemUIDialogManager
    @Mock private lateinit var burnInHelper: BurnInHelperWrapper

    @Before
@@ -70,6 +74,7 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
        keyguardRepository = FakeKeyguardRepository()
        bouncerRepository = FakeKeyguardBouncerRepository()
        fakeCommandQueue = FakeCommandQueue()
        shadeRepository = FakeShadeRepository()
        featureFlags =
            FakeFeatureFlags().apply {
                set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
@@ -93,6 +98,8 @@ class UdfpsAodViewModelTest : SysuiTestCase() {
                    bouncerRepository,
                    configRepository,
                ),
                shadeRepository,
                dialogManager,
            )

        underTest =
Loading