• 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.domain.interactor
18 
19 import android.content.Context
20 import com.android.systemui.dagger.SysUISingleton
21 import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
22 import com.android.systemui.keyguard.shared.model.Edge
23 import com.android.systemui.keyguard.shared.model.KeyguardState
24 import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
25 import com.android.systemui.scene.shared.model.Scenes
26 import com.android.systemui.shade.ShadeDisplayAware
27 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
28 import com.android.systemui.util.kotlin.sample
29 import com.android.systemui.util.kotlin.toPx
30 import dagger.Lazy
31 import javax.inject.Inject
32 import kotlinx.coroutines.flow.Flow
33 import kotlinx.coroutines.flow.combine
34 import kotlinx.coroutines.flow.distinctUntilChanged
35 import kotlinx.coroutines.flow.map
36 import kotlinx.coroutines.flow.onStart
37 
38 /**
39  * Distance over which the surface behind the keyguard is animated in during a Y-translation
40  * animation.
41  */
42 const val SURFACE_TRANSLATION_Y_DISTANCE_DP = 250
43 
44 @SysUISingleton
45 class KeyguardSurfaceBehindInteractor
46 @Inject
47 constructor(
48     private val repository: KeyguardSurfaceBehindRepository,
49     @ShadeDisplayAware context: Context,
50     transitionInteractor: KeyguardTransitionInteractor,
51     inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>,
52     swipeToDismissInteractor: SwipeToDismissInteractor,
53     notificationLaunchInteractor: NotificationLaunchAnimationInteractor,
54 ) {
55     /**
56      * The view params to use for the surface. These params describe the alpha/translation values to
57      * apply, as well as animation parameters if necessary.
58      */
59     val viewParams: Flow<KeyguardSurfaceBehindModel> =
60         combine(
61                 transitionInteractor.isInTransition(
62                     edge = Edge.create(to = Scenes.Gone),
63                     edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE),
64                 ),
65                 transitionInteractor.isFinishedIn(
66                     content = Scenes.Gone,
67                     stateWithoutSceneContainer = KeyguardState.GONE,
68                 ),
69                 notificationLaunchInteractor.isLaunchAnimationRunning,
70             ) { transitioningToGone, isOnGone, notifAnimationRunning ->
71                 // If we're in transition to GONE, special unlock animation params apply.
72                 if (transitioningToGone) {
73                     if (notifAnimationRunning) {
74                         // If the notification launch animation is running, leave the alpha at 0f.
75                         // The ActivityLaunchAnimator will morph it from the notification at the
76                         // appropriate time.
77                         return@combine KeyguardSurfaceBehindModel(alpha = 0f)
78                     } else if (
79                         inWindowLauncherUnlockAnimationInteractor.get().isLauncherUnderneath()
80                     ) {
81                         // The Launcher icons have their own translation/alpha animations during the
82                         // in-window animation. We'll just make the surface visible and let Launcher
83                         // do its thing.
84                         return@combine KeyguardSurfaceBehindModel(alpha = 1f)
85                     } else {
86                         // Otherwise, animate a surface in via alpha/translation, and apply the
87                         // swipe velocity (if available) to the translation spring.
88                         return@combine KeyguardSurfaceBehindModel(
89                             animateFromAlpha = 0f,
90                             alpha = 1f,
91                             animateFromTranslationY =
92                                 SURFACE_TRANSLATION_Y_DISTANCE_DP.toPx(context).toFloat(),
93                             translationY = 0f,
94                             startVelocity =
95                                 swipeToDismissInteractor.dismissFling.value?.velocity ?: 0f,
96                         )
97                     }
98                 }
99 
100                 // Default to the visibility of the current state, with no animations.
101                 KeyguardSurfaceBehindModel(alpha = if (isOnGone) 1f else 0f)
102             }
103             .distinctUntilChanged()
104 
105     /**
106      * Whether a notification launch animation is running when we're not already in the GONE state.
107      */
108     private val isNotificationLaunchAnimationRunningOnKeyguard =
109         notificationLaunchInteractor.isLaunchAnimationRunning
110             .sample(
111                 transitionInteractor.isFinishedIn(
112                     content = Scenes.Gone,
113                     stateWithoutSceneContainer = KeyguardState.GONE,
114                 ),
115                 ::Pair,
116             )
117             .map { (animationRunning, isOnGone) -> animationRunning && !isOnGone }
118             .onStart { emit(false) }
119 
120     /**
121      * Whether we're animating the surface, or a notification launch animation is running (which
122      * means we're going to animate the surface, even if animators aren't yet running).
123      */
124     val isAnimatingSurface =
125         combine(repository.isAnimatingSurface, isNotificationLaunchAnimationRunningOnKeyguard) {
126             animatingSurface,
127             animatingLaunch ->
128             animatingSurface || animatingLaunch
129         }
130 
131     fun setAnimatingSurface(animating: Boolean) {
132         repository.setAnimatingSurface(animating)
133     }
134 
135     fun setSurfaceRemoteAnimationTargetAvailable(available: Boolean) {
136         repository.setSurfaceRemoteAnimationTargetAvailable(available)
137     }
138 }
139