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