• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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