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