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