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 com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION 22 import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor 23 import com.android.systemui.keyguard.shared.model.Edge 24 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE 25 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER 26 import com.android.systemui.keyguard.shared.model.ScrimAlpha 27 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow 28 import com.android.systemui.scene.shared.flag.SceneContainerFlag 29 import com.android.systemui.scene.shared.model.Scenes 30 import com.android.systemui.statusbar.SysuiStatusBarStateController 31 import dagger.Lazy 32 import javax.inject.Inject 33 import kotlin.time.Duration.Companion.milliseconds 34 import kotlinx.coroutines.ExperimentalCoroutinesApi 35 import kotlinx.coroutines.flow.Flow 36 import kotlinx.coroutines.flow.flatMapLatest 37 38 /** 39 * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to 40 * consume. 41 */ 42 @OptIn(ExperimentalCoroutinesApi::class) 43 @SysUISingleton 44 class PrimaryBouncerToGoneTransitionViewModel 45 @Inject 46 constructor( 47 private val statusBarStateController: SysuiStatusBarStateController, 48 private val primaryBouncerInteractor: PrimaryBouncerInteractor, 49 keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, 50 bouncerToGoneFlows: BouncerToGoneFlows, 51 animationFlow: KeyguardTransitionAnimationFlow, 52 ) { 53 private val transitionAnimation = 54 animationFlow 55 .setup( 56 duration = TO_GONE_DURATION, 57 edge = Edge.create(from = PRIMARY_BOUNCER, to = Scenes.Gone), 58 ) 59 .setupWithoutSceneContainer( 60 edge = Edge.create(from = PRIMARY_BOUNCER, to = GONE), 61 ) 62 63 private var leaveShadeOpen: Boolean = false 64 private var willRunDismissFromKeyguard: Boolean = false 65 66 /** See [BouncerToGoneFlows#showAllNotifications] */ 67 val showAllNotifications: Flow<Boolean> = 68 bouncerToGoneFlows.showAllNotifications(TO_GONE_DURATION, PRIMARY_BOUNCER) 69 70 val notificationAlpha: Flow<Float> = 71 transitionAnimation.sharedFlow( 72 duration = 200.milliseconds, <lambda>null73 onStart = { 74 leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() 75 willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard() 76 }, <lambda>null77 onStep = { 78 if (willRunDismissFromKeyguard || leaveShadeOpen) { 79 1f 80 } else { 81 1f - it 82 } 83 }, 84 ) 85 86 /** Bouncer container alpha */ 87 val bouncerAlpha: Flow<Float> = 88 if (SceneContainerFlag.isEnabled) { 89 keyguardDismissActionInteractor 90 .get() 91 .willAnimateDismissActionOnLockscreen <lambda>null92 .flatMapLatest { createBouncerAlphaFlow { it } } 93 } else { 94 createBouncerAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard) 95 } 96 createBouncerAlphaFlownull97 private fun createBouncerAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> { 98 return transitionAnimation.sharedFlow( 99 duration = 200.milliseconds, 100 onStart = { willRunDismissFromKeyguard = willRunAnimationOnKeyguard() }, 101 onStep = { 102 if (willRunDismissFromKeyguard) { 103 0f 104 } else { 105 1f - it 106 } 107 }, 108 ) 109 } 110 111 /** Lockscreen alpha */ 112 val lockscreenAlpha: Flow<Float> = 113 if (SceneContainerFlag.isEnabled) { 114 keyguardDismissActionInteractor 115 .get() 116 .willAnimateDismissActionOnLockscreen <lambda>null117 .flatMapLatest { createLockscreenAlpha { it } } 118 } else { 119 createLockscreenAlpha(primaryBouncerInteractor::willRunDismissFromKeyguard) 120 } 121 createLockscreenAlphanull122 private fun createLockscreenAlpha(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> { 123 return transitionAnimation.sharedFlow( 124 duration = 50.milliseconds, 125 onStart = { 126 leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() 127 willRunDismissFromKeyguard = willRunAnimationOnKeyguard() 128 }, 129 onStep = { 130 if (willRunDismissFromKeyguard || leaveShadeOpen) { 131 1f 132 } else { 133 0f 134 } 135 }, 136 onFinish = { 0f }, 137 ) 138 } 139 140 val scrimAlpha: Flow<ScrimAlpha> = 141 bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, PRIMARY_BOUNCER) 142 } 143