• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.ui.viewmodel
18 
19 import android.util.MathUtils
20 import com.android.systemui.Flags
21 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
22 import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
25 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_SHORT_DURATION
26 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
27 import com.android.systemui.keyguard.shared.model.Edge
28 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
29 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
30 import com.android.systemui.keyguard.shared.model.ScrimAlpha
31 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
32 import com.android.systemui.keyguard.ui.transitions.BlurConfig
33 import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition
34 import com.android.systemui.statusbar.SysuiStatusBarStateController
35 import dagger.Lazy
36 import javax.inject.Inject
37 import kotlin.time.Duration.Companion.milliseconds
38 import kotlinx.coroutines.flow.Flow
39 import kotlinx.coroutines.flow.flatMapLatest
40 
41 /**
42  * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
43  * consume.
44  */
45 @SysUISingleton
46 class PrimaryBouncerToGoneTransitionViewModel
47 @Inject
48 constructor(
49     private val blurConfig: BlurConfig,
50     private val statusBarStateController: SysuiStatusBarStateController,
51     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
52     keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
53     bouncerToGoneFlows: BouncerToGoneFlows,
54     animationFlow: KeyguardTransitionAnimationFlow,
55 ) : PrimaryBouncerTransition {
56     private val transitionAnimation =
57         animationFlow
58             .setup(duration = TO_GONE_DURATION, edge = Edge.INVALID)
59             .setupWithoutSceneContainer(edge = Edge.create(from = PRIMARY_BOUNCER, to = GONE))
60 
61     private var leaveShadeOpen: Boolean = false
62     private var willRunDismissFromKeyguard: Boolean = false
63 
64     /** See [BouncerToGoneFlows#showAllNotifications] */
65     val showAllNotifications: Flow<Boolean> =
66         bouncerToGoneFlows.showAllNotifications(TO_GONE_DURATION, PRIMARY_BOUNCER)
67 
notificationAlphanull68     fun notificationAlpha(viewState: ViewStateAccessor): Flow<Float> {
69         var startAlpha = 1f
70         return transitionAnimation.sharedFlow(
71             duration = 200.milliseconds,
72             onStart = {
73                 startAlpha = viewState.alpha()
74                 leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
75                 willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
76             },
77             onStep = {
78                 if (willRunDismissFromKeyguard || leaveShadeOpen) {
79                     1f
80                 } else {
81                     MathUtils.lerp(startAlpha, 0f, it)
82                 }
83             },
84             onFinish = { 1f },
85         )
86     }
87 
88     /** Bouncer container alpha */
89     val bouncerAlpha: Flow<Float> =
90         if (ComposeBouncerFlags.isEnabled) {
91             keyguardDismissActionInteractor
92                 .get()
93                 .willAnimateDismissActionOnLockscreen
<lambda>null94                 .flatMapLatest { createBouncerAlphaFlow { it } }
95         } else {
96             createBouncerAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard)
97         }
98 
createBouncerAlphaFlownull99     private fun createBouncerAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> {
100         return transitionAnimation.sharedFlow(
101             duration = TO_GONE_SHORT_DURATION,
102             onStart = { willRunDismissFromKeyguard = willRunAnimationOnKeyguard() },
103             onStep = {
104                 if (willRunDismissFromKeyguard) {
105                     0f
106                 } else {
107                     1f - it
108                 }
109             },
110         )
111     }
112 
createBouncerWindowBlurFlownull113     private fun createBouncerWindowBlurFlow(): Flow<Float> {
114         return transitionAnimation.sharedFlow(
115             duration = TO_GONE_SHORT_DURATION,
116             onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() },
117             onStep = {
118                 if (leaveShadeOpen && Flags.notificationShadeBlur()) {
119                     // Going back to shade from bouncer after keyguard dismissal
120                     blurConfig.maxBlurRadiusPx
121                 } else {
122                     transitionProgressToBlurRadius(
123                         starBlurRadius = blurConfig.maxBlurRadiusPx,
124                         endBlurRadius = blurConfig.minBlurRadiusPx,
125                         transitionProgress = it,
126                     )
127                 }
128             },
129         )
130     }
131 
132     /** Lockscreen alpha */
133     val lockscreenAlpha: Flow<Float> =
134         if (ComposeBouncerFlags.isEnabled) {
135             keyguardDismissActionInteractor
136                 .get()
137                 .willAnimateDismissActionOnLockscreen
<lambda>null138                 .flatMapLatest { createLockscreenAlpha { it } }
139         } else {
140             createLockscreenAlpha(primaryBouncerInteractor::willRunDismissFromKeyguard)
141         }
142 
createLockscreenAlphanull143     private fun createLockscreenAlpha(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> {
144         return transitionAnimation.sharedFlow(
145             duration = 50.milliseconds,
146             onStart = {
147                 leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
148                 willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
149             },
150             onStep = {
151                 if (willRunDismissFromKeyguard || leaveShadeOpen) {
152                     1f
153                 } else {
154                     0f
155                 }
156             },
157             onFinish = { 0f },
158         )
159     }
160 
161     override val windowBlurRadius: Flow<Float> = createBouncerWindowBlurFlow()
162 
163     override val notificationBlurRadius: Flow<Float> =
164         transitionAnimation.immediatelyTransitionTo(0.0f)
165 
166     val scrimAlpha: Flow<ScrimAlpha> =
167         bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, PRIMARY_BOUNCER)
168 }
169