1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.keyguard.domain.interactor 18 19 import com.android.keyguard.logging.ScrimLogger 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.dagger.qualifiers.Application 22 import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository 23 import com.android.systemui.keyguard.shared.model.KeyguardState 24 import com.android.systemui.power.domain.interactor.PowerInteractor 25 import com.android.systemui.power.shared.model.ScreenPowerState 26 import com.android.systemui.statusbar.LightRevealEffect 27 import com.android.systemui.util.kotlin.sample 28 import dagger.Lazy 29 import javax.inject.Inject 30 import kotlinx.coroutines.CoroutineScope 31 import kotlinx.coroutines.flow.Flow 32 import kotlinx.coroutines.flow.filter 33 import kotlinx.coroutines.launch 34 35 @SysUISingleton 36 class LightRevealScrimInteractor 37 @Inject 38 constructor( 39 private val transitionInteractor: KeyguardTransitionInteractor, 40 private val lightRevealScrimRepository: LightRevealScrimRepository, 41 @Application private val scope: CoroutineScope, 42 private val scrimLogger: ScrimLogger, 43 private val powerInteractor: Lazy<PowerInteractor>, 44 ) { 45 init { 46 listenForStartedKeyguardTransitionStep() 47 } 48 listenForStartedKeyguardTransitionStepnull49 private fun listenForStartedKeyguardTransitionStep() { 50 scope.launch { 51 transitionInteractor.startedKeyguardTransitionStep.collect { 52 scrimLogger.d(TAG, "listenForStartedKeyguardTransitionStep", it) 53 lightRevealScrimRepository.startRevealAmountAnimator(willBeRevealedInState(it.to)) 54 } 55 } 56 } 57 58 /** 59 * Whenever a keyguard transition starts, sample the latest reveal effect from the repository 60 * and use that for the starting transition. 61 * 62 * We can't simply use the nextRevealEffect since the effect may change midway through a 63 * transition, but we don't want to change effects part way through. For example, if we're using 64 * a CircleReveal to animate a biometric unlock, but the biometric unlock mode changes to NONE 65 * from WAKE_AND_UNLOCK before the unlock animation ends, we don't want to end up switching to a 66 * LiftReveal. 67 */ 68 val lightRevealEffect: Flow<LightRevealEffect> = 69 transitionInteractor.startedKeyguardTransitionStep.sample( 70 lightRevealScrimRepository.revealEffect 71 ) 72 73 val revealAmount = <lambda>null74 lightRevealScrimRepository.revealAmount.filter { 75 // When the screen is off we do not want to keep producing frames as this is causing 76 // (invisible) jank. However, we need to still pass through 1f and 0f to ensure that the 77 // correct end states are respected even if the screen turned off (or was still off) 78 // when the animation finished 79 screenIsShowingContent() || it == 1f || it == 0f 80 } 81 screenIsShowingContentnull82 private fun screenIsShowingContent() = 83 powerInteractor.get().screenPowerState.value != ScreenPowerState.SCREEN_OFF && 84 powerInteractor.get().screenPowerState.value != ScreenPowerState.SCREEN_TURNING_ON 85 86 val isAnimating: Boolean 87 get() = lightRevealScrimRepository.isAnimating 88 89 /** 90 * Whether the light reveal scrim will be fully revealed (revealAmount = 1.0f) in the given 91 * state after the transition is complete. If false, scrim will be fully hidden. 92 */ 93 private fun willBeRevealedInState(state: KeyguardState): Boolean { 94 return when (state) { 95 KeyguardState.OFF -> false 96 KeyguardState.DOZING -> false 97 KeyguardState.AOD -> false 98 KeyguardState.DREAMING -> true 99 KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> true 100 KeyguardState.GLANCEABLE_HUB -> true 101 KeyguardState.ALTERNATE_BOUNCER -> true 102 KeyguardState.PRIMARY_BOUNCER -> true 103 KeyguardState.LOCKSCREEN -> true 104 KeyguardState.GONE -> true 105 KeyguardState.OCCLUDED -> true 106 KeyguardState.UNDEFINED -> true 107 } 108 } 109 110 companion object { 111 val TAG = LightRevealScrimInteractor::class.simpleName!! 112 } 113 } 114