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