1 /* <lambda>null2 * Copyright (C) 2024 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.statusbar.domain.interactor 18 19 import com.android.systemui.dagger.SysUISingleton 20 import com.android.systemui.keyguard.domain.interactor.KeyguardOcclusionInteractor 21 import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor 22 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 23 import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor 24 import com.android.systemui.keyguard.shared.model.KeyguardState 25 import com.android.systemui.power.domain.interactor.PowerInteractor 26 import com.android.systemui.util.kotlin.sample 27 import javax.inject.Inject 28 import kotlinx.coroutines.flow.Flow 29 import kotlinx.coroutines.flow.combine 30 import kotlinx.coroutines.flow.distinctUntilChanged 31 import kotlinx.coroutines.flow.distinctUntilChangedBy 32 import kotlinx.coroutines.flow.filterNotNull 33 import kotlinx.coroutines.flow.map 34 import kotlinx.coroutines.flow.merge 35 36 /** 37 * Whether to set the status bar keyguard view occluded or not, and whether to animate that change. 38 */ 39 data class OccludedState( 40 val occluded: Boolean, 41 val animate: Boolean = false, 42 ) 43 44 /** Handles logic around calls to [StatusBarKeyguardViewManager] in legacy code. */ 45 @Deprecated("Will be removed once all of SBKVM's responsibilies are refactored.") 46 @SysUISingleton 47 class StatusBarKeyguardViewManagerInteractor 48 @Inject 49 constructor( 50 keyguardTransitionInteractor: KeyguardTransitionInteractor, 51 keyguardOcclusionInteractor: KeyguardOcclusionInteractor, 52 powerInteractor: PowerInteractor, 53 wmLockscreenVisibilityInteractor: WindowManagerLockscreenVisibilityInteractor, 54 surfaceBehindInteractor: KeyguardSurfaceBehindInteractor, 55 ) { 56 /** Occlusion state to apply whenever a keyguard transition is STARTED, if any. */ 57 private val occlusionStateFromStartedStep: Flow<OccludedState> = 58 keyguardTransitionInteractor.startedKeyguardTransitionStep 59 .sample(powerInteractor.detailedWakefulness, ::Pair) 60 .map { (startedStep, wakefulness) -> 61 val transitioningFromPowerButtonGesture = 62 KeyguardState.deviceIsAsleepInState(startedStep.from) && 63 startedStep.to == KeyguardState.OCCLUDED && 64 wakefulness.powerButtonLaunchGestureTriggered 65 66 if ( 67 startedStep.to == KeyguardState.OCCLUDED && !transitioningFromPowerButtonGesture 68 ) { 69 // Set occluded upon STARTED, *unless* we're transitioning from the power 70 // button, in which case we're going to play an animation over the lockscreen UI 71 // and need to remain unoccluded until the transition finishes. 72 return@map OccludedState(occluded = true, animate = false) 73 } 74 75 if ( 76 startedStep.from == KeyguardState.OCCLUDED && 77 startedStep.to == KeyguardState.LOCKSCREEN 78 ) { 79 // Set unoccluded immediately ONLY if we're transitioning back to the lockscreen 80 // since we need the views visible to animate them back down. This is a special 81 // case due to the way unocclusion remote animations are run. We can remove this 82 // once the unocclude animation uses the return animation framework. 83 return@map OccludedState(occluded = false, animate = false) 84 } 85 86 // Otherwise, wait for the transition to FINISH to decide. 87 return@map null 88 } 89 .filterNotNull() 90 91 /** Occlusion state to apply whenever a keyguard transition is FINISHED. */ 92 private val occlusionStateFromFinishedStep = 93 keyguardTransitionInteractor.finishedKeyguardTransitionStep 94 .sample(keyguardOcclusionInteractor.isShowWhenLockedActivityOnTop, ::Pair) 95 .map { (finishedStep, showWhenLockedOnTop) -> 96 // If we're FINISHED in OCCLUDED, we want to render as occluded. We also need to 97 // remain occluded if a SHOW_WHEN_LOCKED activity is on the top of the task stack, 98 // and we're in any state other than GONE. This is necessary, for example, when we 99 // transition from OCCLUDED to a bouncer state. Otherwise, we should not be 100 // occluded. 101 val occluded = 102 finishedStep.to == KeyguardState.OCCLUDED || 103 (showWhenLockedOnTop && finishedStep.to != KeyguardState.GONE) 104 OccludedState(occluded = occluded, animate = false) 105 } 106 107 /** Occlusion state to apply to SBKVM's setOccluded call. */ 108 val keyguardViewOcclusionState = 109 merge(occlusionStateFromStartedStep, occlusionStateFromFinishedStep) 110 .distinctUntilChangedBy { 111 // Don't switch 'animate' values mid-transition. 112 it.occluded 113 } 114 115 /** Visibility state to apply to SBKVM via show() and hide(). */ 116 val keyguardViewVisibility = 117 combine( 118 wmLockscreenVisibilityInteractor.lockscreenVisibility, 119 surfaceBehindInteractor.isAnimatingSurface, 120 ) { lockscreenVisible, animatingSurface -> 121 lockscreenVisible || animatingSurface 122 } 123 .distinctUntilChanged() 124 } 125