1 /* <lambda>null2 * 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.app.animation.Interpolators.EMPHASIZED_DECELERATE 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor 22 import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_AOD_DURATION 23 import com.android.systemui.keyguard.shared.model.Edge 24 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD 25 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE 26 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow 27 import com.android.systemui.keyguard.ui.StateToValue 28 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition 29 import com.android.systemui.power.domain.interactor.PowerInteractor 30 import com.android.systemui.power.shared.model.WakeSleepReason.FOLD 31 import com.android.systemui.scene.shared.model.Scenes 32 import com.android.systemui.util.kotlin.sample 33 import javax.inject.Inject 34 import kotlin.time.Duration.Companion.milliseconds 35 import kotlinx.coroutines.flow.Flow 36 import kotlinx.coroutines.flow.emptyFlow 37 import kotlinx.coroutines.flow.flatMapLatest 38 import kotlinx.coroutines.flow.transform 39 40 /** Breaks down GONE->AOD transition into discrete steps for corresponding views to consume. */ 41 @SysUISingleton 42 class GoneToAodTransitionViewModel 43 @Inject 44 constructor( 45 deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, 46 private val powerInteractor: PowerInteractor, 47 animationFlow: KeyguardTransitionAnimationFlow, 48 ) : DeviceEntryIconTransition { 49 50 private val transitionAnimation = 51 animationFlow 52 .setup( 53 duration = TO_AOD_DURATION, 54 edge = Edge.create(from = Scenes.Gone, to = AOD), 55 ) 56 .setupWithoutSceneContainer( 57 edge = Edge.create(from = GONE, to = AOD), 58 ) 59 60 /** y-translation from the top of the screen for AOD */ 61 fun enterFromTopTranslationY(translatePx: Int): Flow<StateToValue> { 62 return transitionAnimation 63 .sharedFlowWithState( 64 startTime = 600.milliseconds, 65 duration = 500.milliseconds, 66 onStep = { translatePx + it * -translatePx }, 67 onFinish = { 0f }, 68 interpolator = EMPHASIZED_DECELERATE, 69 ) 70 .sample(powerInteractor.detailedWakefulness, ::Pair) 71 .transform { (stateToValue, wakefulness) -> 72 if (wakefulness.lastSleepReason != FOLD) { 73 emit(stateToValue) 74 } 75 } 76 } 77 78 /** x-translation from the side of the screen for fold animation */ 79 fun enterFromSideTranslationX(translatePx: Int): Flow<StateToValue> { 80 return transitionAnimation 81 .sharedFlowWithState( 82 startTime = 500.milliseconds, 83 duration = 600.milliseconds, 84 onStep = { translatePx + it * -translatePx }, 85 onFinish = { 0f }, 86 interpolator = EMPHASIZED_DECELERATE, 87 ) 88 .sample(powerInteractor.detailedWakefulness, ::Pair) 89 .transform { (stateToValue, wakefulness) -> 90 if (wakefulness.lastSleepReason == FOLD) { 91 emit(stateToValue) 92 } 93 } 94 } 95 96 val notificationAlpha: Flow<Float> = 97 transitionAnimation.sharedFlow( 98 duration = 200.milliseconds, 99 onStep = { 1f - it }, 100 // Needs to be 1f in order for HUNs to appear on AOD 101 onFinish = { 1f }, 102 ) 103 104 /** alpha animation upon entering AOD */ 105 val enterFromTopAnimationAlpha: Flow<Float> = 106 transitionAnimation.sharedFlow( 107 startTime = 700.milliseconds, 108 duration = 400.milliseconds, 109 onStep = { it }, 110 onFinish = { 1f }, 111 ) 112 val deviceEntryBackgroundViewAlpha: Flow<Float> = 113 transitionAnimation.immediatelyTransitionTo(0f) 114 override val deviceEntryParentViewAlpha: Flow<Float> = 115 deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled -> 116 if (udfpsEnrolled) { 117 // fade in at the end of the transition to give time for FP to start running 118 // and avoid a flicker of the unlocked icon 119 transitionAnimation.sharedFlow( 120 startTime = 1100.milliseconds, 121 duration = 200.milliseconds, 122 onStep = { it }, 123 onCancel = { 1f }, 124 onFinish = { 1f }, 125 ) 126 } else { 127 emptyFlow() 128 } 129 } 130 } 131