Loading packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt +33 −6 Original line number Diff line number Diff line Loading @@ -20,10 +20,13 @@ package com.android.systemui.keyguard.data.repository import android.content.Context import android.graphics.Point import androidx.core.animation.Animator import androidx.core.animation.ValueAnimator import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.WakeSleepReason.TAP import com.android.systemui.statusbar.CircleReveal import com.android.systemui.statusbar.LiftReveal import com.android.systemui.statusbar.LightRevealEffect Loading @@ -31,9 +34,12 @@ import com.android.systemui.statusbar.PowerButtonReveal import javax.inject.Inject import kotlin.math.max import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map Loading @@ -52,6 +58,10 @@ interface LightRevealScrimRepository { * at the current screen position of the appropriate sensor. */ val revealEffect: Flow<LightRevealEffect> val revealAmount: Flow<Float> fun startRevealAmountAnimator(reveal: Boolean) } @SysUISingleton Loading Loading @@ -108,14 +118,31 @@ constructor( /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */ private val nonBiometricRevealEffect: Flow<LightRevealEffect?> = keyguardRepository.wakefulness.flatMapLatest { wakefulnessModel -> keyguardRepository.wakefulness .filter { it.isStartingToWake() || it.isStartingToSleep() } .flatMapLatest { wakefulnessModel -> when { wakefulnessModel.isTransitioningFromPowerButton() -> powerButtonRevealEffect wakefulnessModel.isAwakeFromTap() -> tapRevealEffect wakefulnessModel.isWakingFrom(TAP) -> tapRevealEffect else -> flowOf(LiftReveal) } } private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 } override val revealAmount: Flow<Float> = callbackFlow { val updateListener = Animator.AnimatorUpdateListener { trySend((it as ValueAnimator).animatedValue as Float) } revealAmountAnimator.addUpdateListener(updateListener) awaitClose { revealAmountAnimator.removeUpdateListener(updateListener) } } override fun startRevealAmountAnimator(reveal: Boolean) { if (reveal) revealAmountAnimator.start() else revealAmountAnimator.reverse() } override val revealEffect = combine( keyguardRepository.biometricUnlockState, Loading packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +24 −18 Original line number Diff line number Diff line Loading @@ -17,28 +17,44 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @ExperimentalCoroutinesApi @SysUISingleton class LightRevealScrimInteractor @Inject constructor( transitionRepository: KeyguardTransitionRepository, transitionInteractor: KeyguardTransitionInteractor, lightRevealScrimRepository: LightRevealScrimRepository, private val transitionInteractor: KeyguardTransitionInteractor, private val lightRevealScrimRepository: LightRevealScrimRepository, @Application private val scope: CoroutineScope, ) { init { listenForStartedKeyguardTransitionStep() } private fun listenForStartedKeyguardTransitionStep() { scope.launch { transitionInteractor.startedKeyguardTransitionStep.collect { if (willTransitionChangeEndState(it)) { lightRevealScrimRepository.startRevealAmountAnimator( willBeRevealedInState(it.to) ) } } } } /** * Whenever a keyguard transition starts, sample the latest reveal effect from the repository * and use that for the starting transition. Loading @@ -54,17 +70,7 @@ constructor( lightRevealScrimRepository.revealEffect ) /** * The reveal amount to use for the light reveal scrim, which is derived from the keyguard * transition steps. */ val revealAmount: Flow<Float> = transitionRepository.transitions // Only listen to transitions that change the reveal amount. .filter { willTransitionAffectRevealAmount(it) } // Use the transition amount as the reveal amount, inverting it if we're transitioning // to a non-revealed (hidden) state. .map { step -> if (willBeRevealedInState(step.to)) step.value else 1f - step.value } val revealAmount = lightRevealScrimRepository.revealAmount companion object { Loading @@ -72,7 +78,7 @@ constructor( * Whether the transition requires a change in the reveal amount of the light reveal scrim. * If not, we don't care about the transition and don't need to listen to it. */ fun willTransitionAffectRevealAmount(transition: TransitionStep): Boolean { fun willTransitionChangeEndState(transition: TransitionStep): Boolean { return willBeRevealedInState(transition.from) != willBeRevealedInState(transition.to) } Loading packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt +20 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,13 @@ package com.android.systemui.keyguard.shared.model import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.WakeSleepReason.GESTURE import com.android.systemui.keyguard.shared.model.WakeSleepReason.POWER_BUTTON import com.android.systemui.keyguard.shared.model.WakeSleepReason.TAP import com.android.systemui.keyguard.shared.model.WakefulnessState.ASLEEP import com.android.systemui.keyguard.shared.model.WakefulnessState.AWAKE import com.android.systemui.keyguard.shared.model.WakefulnessState.STARTING_TO_SLEEP import com.android.systemui.keyguard.shared.model.WakefulnessState.STARTING_TO_WAKE /** Model device wakefulness states. */ data class WakefulnessModel( Loading @@ -23,33 +30,31 @@ data class WakefulnessModel( val lastWakeReason: WakeSleepReason, val lastSleepReason: WakeSleepReason, ) { fun isStartingToWake() = state == WakefulnessState.STARTING_TO_WAKE fun isStartingToWake() = state == STARTING_TO_WAKE fun isStartingToSleep() = state == WakefulnessState.STARTING_TO_SLEEP fun isStartingToSleep() = state == STARTING_TO_SLEEP private fun isAsleep() = state == WakefulnessState.ASLEEP private fun isAsleep() = state == ASLEEP private fun isAwake() = state == AWAKE fun isStartingToWakeOrAwake() = isStartingToWake() || isAwake() fun isStartingToSleepOrAsleep() = isStartingToSleep() || isAsleep() fun isDeviceInteractive() = !isAsleep() fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE fun isWakingFrom(wakeSleepReason: WakeSleepReason) = isStartingToWake() && lastWakeReason == wakeSleepReason fun isStartingToSleepFromPowerButton() = isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON fun isWakingFromPowerButton() = isStartingToWake() && lastWakeReason == WakeSleepReason.POWER_BUTTON fun isStartingToSleepFrom(wakeSleepReason: WakeSleepReason) = isStartingToSleep() && lastSleepReason == wakeSleepReason fun isTransitioningFromPowerButton() = isStartingToSleepFromPowerButton() || isWakingFromPowerButton() fun isAwakeFromTap() = state == WakefulnessState.STARTING_TO_WAKE && lastWakeReason == WakeSleepReason.TAP isStartingToSleepFrom(POWER_BUTTON) || isWakingFrom(POWER_BUTTON) fun isDeviceInteractiveFromTapOrGesture(): Boolean { return isDeviceInteractive() && (lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE) return isDeviceInteractive() && (lastWakeReason == TAP || lastWakeReason == GESTURE) } companion object { Loading packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt +2 −4 Original line number Diff line number Diff line Loading @@ -20,20 +20,18 @@ import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map /** View-model for the keyguard indication area view */ @OptIn(ExperimentalCoroutinesApi::class) class KeyguardIndicationAreaViewModel @Inject constructor( private val keyguardInteractor: KeyguardInteractor, private val bottomAreaInteractor: KeyguardBottomAreaInteractor, private val keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, bottomAreaInteractor: KeyguardBottomAreaInteractor, keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, private val burnInHelperWrapper: BurnInHelperWrapper, ) { Loading packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt +2 −0 Original line number Diff line number Diff line Loading @@ -19,12 +19,14 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.domain.interactor.LightRevealScrimInteractor import com.android.systemui.statusbar.LightRevealEffect import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow /** * Models UI state for the light reveal scrim, which is used during screen on and off animations to * draw a gradient that reveals/hides the contents of the screen. */ @OptIn(ExperimentalCoroutinesApi::class) class LightRevealScrimViewModel @Inject constructor(interactor: LightRevealScrimInteractor) { val lightRevealEffect: Flow<LightRevealEffect> = interactor.lightRevealEffect val revealAmount: Flow<Float> = interactor.revealAmount Loading Loading
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt +33 −6 Original line number Diff line number Diff line Loading @@ -20,10 +20,13 @@ package com.android.systemui.keyguard.data.repository import android.content.Context import android.graphics.Point import androidx.core.animation.Animator import androidx.core.animation.ValueAnimator import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.WakeSleepReason.TAP import com.android.systemui.statusbar.CircleReveal import com.android.systemui.statusbar.LiftReveal import com.android.systemui.statusbar.LightRevealEffect Loading @@ -31,9 +34,12 @@ import com.android.systemui.statusbar.PowerButtonReveal import javax.inject.Inject import kotlin.math.max import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map Loading @@ -52,6 +58,10 @@ interface LightRevealScrimRepository { * at the current screen position of the appropriate sensor. */ val revealEffect: Flow<LightRevealEffect> val revealAmount: Flow<Float> fun startRevealAmountAnimator(reveal: Boolean) } @SysUISingleton Loading Loading @@ -108,14 +118,31 @@ constructor( /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */ private val nonBiometricRevealEffect: Flow<LightRevealEffect?> = keyguardRepository.wakefulness.flatMapLatest { wakefulnessModel -> keyguardRepository.wakefulness .filter { it.isStartingToWake() || it.isStartingToSleep() } .flatMapLatest { wakefulnessModel -> when { wakefulnessModel.isTransitioningFromPowerButton() -> powerButtonRevealEffect wakefulnessModel.isAwakeFromTap() -> tapRevealEffect wakefulnessModel.isWakingFrom(TAP) -> tapRevealEffect else -> flowOf(LiftReveal) } } private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 } override val revealAmount: Flow<Float> = callbackFlow { val updateListener = Animator.AnimatorUpdateListener { trySend((it as ValueAnimator).animatedValue as Float) } revealAmountAnimator.addUpdateListener(updateListener) awaitClose { revealAmountAnimator.removeUpdateListener(updateListener) } } override fun startRevealAmountAnimator(reveal: Boolean) { if (reveal) revealAmountAnimator.start() else revealAmountAnimator.reverse() } override val revealEffect = combine( keyguardRepository.biometricUnlockState, Loading
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +24 −18 Original line number Diff line number Diff line Loading @@ -17,28 +17,44 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @ExperimentalCoroutinesApi @SysUISingleton class LightRevealScrimInteractor @Inject constructor( transitionRepository: KeyguardTransitionRepository, transitionInteractor: KeyguardTransitionInteractor, lightRevealScrimRepository: LightRevealScrimRepository, private val transitionInteractor: KeyguardTransitionInteractor, private val lightRevealScrimRepository: LightRevealScrimRepository, @Application private val scope: CoroutineScope, ) { init { listenForStartedKeyguardTransitionStep() } private fun listenForStartedKeyguardTransitionStep() { scope.launch { transitionInteractor.startedKeyguardTransitionStep.collect { if (willTransitionChangeEndState(it)) { lightRevealScrimRepository.startRevealAmountAnimator( willBeRevealedInState(it.to) ) } } } } /** * Whenever a keyguard transition starts, sample the latest reveal effect from the repository * and use that for the starting transition. Loading @@ -54,17 +70,7 @@ constructor( lightRevealScrimRepository.revealEffect ) /** * The reveal amount to use for the light reveal scrim, which is derived from the keyguard * transition steps. */ val revealAmount: Flow<Float> = transitionRepository.transitions // Only listen to transitions that change the reveal amount. .filter { willTransitionAffectRevealAmount(it) } // Use the transition amount as the reveal amount, inverting it if we're transitioning // to a non-revealed (hidden) state. .map { step -> if (willBeRevealedInState(step.to)) step.value else 1f - step.value } val revealAmount = lightRevealScrimRepository.revealAmount companion object { Loading @@ -72,7 +78,7 @@ constructor( * Whether the transition requires a change in the reveal amount of the light reveal scrim. * If not, we don't care about the transition and don't need to listen to it. */ fun willTransitionAffectRevealAmount(transition: TransitionStep): Boolean { fun willTransitionChangeEndState(transition: TransitionStep): Boolean { return willBeRevealedInState(transition.from) != willBeRevealedInState(transition.to) } Loading
packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt +20 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,13 @@ package com.android.systemui.keyguard.shared.model import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.WakeSleepReason.GESTURE import com.android.systemui.keyguard.shared.model.WakeSleepReason.POWER_BUTTON import com.android.systemui.keyguard.shared.model.WakeSleepReason.TAP import com.android.systemui.keyguard.shared.model.WakefulnessState.ASLEEP import com.android.systemui.keyguard.shared.model.WakefulnessState.AWAKE import com.android.systemui.keyguard.shared.model.WakefulnessState.STARTING_TO_SLEEP import com.android.systemui.keyguard.shared.model.WakefulnessState.STARTING_TO_WAKE /** Model device wakefulness states. */ data class WakefulnessModel( Loading @@ -23,33 +30,31 @@ data class WakefulnessModel( val lastWakeReason: WakeSleepReason, val lastSleepReason: WakeSleepReason, ) { fun isStartingToWake() = state == WakefulnessState.STARTING_TO_WAKE fun isStartingToWake() = state == STARTING_TO_WAKE fun isStartingToSleep() = state == WakefulnessState.STARTING_TO_SLEEP fun isStartingToSleep() = state == STARTING_TO_SLEEP private fun isAsleep() = state == WakefulnessState.ASLEEP private fun isAsleep() = state == ASLEEP private fun isAwake() = state == AWAKE fun isStartingToWakeOrAwake() = isStartingToWake() || isAwake() fun isStartingToSleepOrAsleep() = isStartingToSleep() || isAsleep() fun isDeviceInteractive() = !isAsleep() fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE fun isWakingFrom(wakeSleepReason: WakeSleepReason) = isStartingToWake() && lastWakeReason == wakeSleepReason fun isStartingToSleepFromPowerButton() = isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON fun isWakingFromPowerButton() = isStartingToWake() && lastWakeReason == WakeSleepReason.POWER_BUTTON fun isStartingToSleepFrom(wakeSleepReason: WakeSleepReason) = isStartingToSleep() && lastSleepReason == wakeSleepReason fun isTransitioningFromPowerButton() = isStartingToSleepFromPowerButton() || isWakingFromPowerButton() fun isAwakeFromTap() = state == WakefulnessState.STARTING_TO_WAKE && lastWakeReason == WakeSleepReason.TAP isStartingToSleepFrom(POWER_BUTTON) || isWakingFrom(POWER_BUTTON) fun isDeviceInteractiveFromTapOrGesture(): Boolean { return isDeviceInteractive() && (lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE) return isDeviceInteractive() && (lastWakeReason == TAP || lastWakeReason == GESTURE) } companion object { Loading
packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt +2 −4 Original line number Diff line number Diff line Loading @@ -20,20 +20,18 @@ import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map /** View-model for the keyguard indication area view */ @OptIn(ExperimentalCoroutinesApi::class) class KeyguardIndicationAreaViewModel @Inject constructor( private val keyguardInteractor: KeyguardInteractor, private val bottomAreaInteractor: KeyguardBottomAreaInteractor, private val keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, bottomAreaInteractor: KeyguardBottomAreaInteractor, keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, private val burnInHelperWrapper: BurnInHelperWrapper, ) { Loading
packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt +2 −0 Original line number Diff line number Diff line Loading @@ -19,12 +19,14 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.domain.interactor.LightRevealScrimInteractor import com.android.systemui.statusbar.LightRevealEffect import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow /** * Models UI state for the light reveal scrim, which is used during screen on and off animations to * draw a gradient that reveals/hides the contents of the screen. */ @OptIn(ExperimentalCoroutinesApi::class) class LightRevealScrimViewModel @Inject constructor(interactor: LightRevealScrimInteractor) { val lightRevealEffect: Flow<LightRevealEffect> = interactor.lightRevealEffect val revealAmount: Flow<Float> = interactor.revealAmount Loading