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.binder
18 
19 import android.animation.Animator
20 import android.animation.AnimatorListenerAdapter
21 import android.animation.ValueAnimator
22 import android.graphics.Matrix
23 import android.util.Log
24 import android.view.RemoteAnimationTarget
25 import android.view.SurfaceControl
26 import android.view.SyncRtSurfaceTransactionApplier
27 import android.view.View
28 import androidx.dynamicanimation.animation.FloatValueHolder
29 import androidx.dynamicanimation.animation.SpringAnimation
30 import androidx.dynamicanimation.animation.SpringForce
31 import com.android.keyguard.KeyguardViewController
32 import com.android.systemui.dagger.SysUISingleton
33 import com.android.systemui.dagger.qualifiers.Main
34 import com.android.systemui.keyguard.TAG
35 import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor
36 import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
37 import com.android.wm.shell.animation.Interpolators
38 import java.util.concurrent.Executor
39 import javax.inject.Inject
40 
41 /**
42  * Applies [KeyguardSurfaceBehindViewParams] to a RemoteAnimationTarget, starting and managing
43  * animations as needed.
44  */
45 @SysUISingleton
46 class KeyguardSurfaceBehindParamsApplier
47 @Inject
48 constructor(
49     @Main private val executor: Executor,
50     private val keyguardViewController: KeyguardViewController,
51     private val interactor: KeyguardSurfaceBehindInteractor,
52 ) {
53     private var surfaceBehind: RemoteAnimationTarget? = null
54         set(value) {
55             field = value
56             interactor.setSurfaceRemoteAnimationTargetAvailable(value != null)
57         }
58 
59     private val surfaceTransactionApplier: SyncRtSurfaceTransactionApplier
60         get() = SyncRtSurfaceTransactionApplier(keyguardViewController.viewRootImpl.view)
61 
62     private val matrix = Matrix()
63     private val tmpFloat = FloatArray(9)
64 
65     private var animatedTranslationY = FloatValueHolder()
66     private val translateYSpring =
67         SpringAnimation(animatedTranslationY).apply {
68             spring =
69                 SpringForce().apply {
70                     stiffness = 275f
71                     dampingRatio = 0.98f
72                 }
73             addUpdateListener { _, _, _ -> applyToSurfaceBehind() }
74             addEndListener { _, _, _, _ ->
75                 try {
76                     updateIsAnimatingSurface()
77                 } catch (e: NullPointerException) {
78                     // TODO(b/291645410): Remove when we can isolate DynamicAnimations.
79                     e.printStackTrace()
80                 }
81             }
82         }
83 
84     private var animatedAlpha = 0f
85     private var alphaAnimator =
86         ValueAnimator.ofFloat(0f, 1f).apply {
87             duration = 150
88             interpolator = Interpolators.ALPHA_IN
89             addUpdateListener {
90                 animatedAlpha = it.animatedValue as Float
91                 applyToSurfaceBehind()
92             }
93             addListener(
94                 object : AnimatorListenerAdapter() {
95                     override fun onAnimationEnd(animation: Animator) {
96                         updateIsAnimatingSurface()
97                     }
98                 }
99             )
100         }
101 
102     /**
103      * ViewParams to apply to the surface provided to [applyParamsToSurface]. If the surface is null
104      * these will be applied once someone gives us a surface via [applyParamsToSurface].
105      */
106     var viewParams: KeyguardSurfaceBehindModel = KeyguardSurfaceBehindModel()
107         set(newParams) {
108             field = newParams
109             startOrUpdateAnimators()
110             applyToSurfaceBehind()
111         }
112 
113     /**
114      * Provides us with a surface to animate. We'll apply the [viewParams] to this surface and start
115      * any necessary animations.
116      */
117     fun applyParamsToSurface(surface: RemoteAnimationTarget) {
118         this.surfaceBehind = surface
119         startOrUpdateAnimators()
120         applyToSurfaceBehind()
121     }
122 
123     /**
124      * Notifies us that the [RemoteAnimationTarget] has been released, one way or another.
125      * Attempting to animate a released target will cause a crash.
126      *
127      * This can be called either because we finished animating the surface naturally, or by WM
128      * because external factors cancelled the remote animation (timeout, re-lock, etc). If it's the
129      * latter, cancel any outstanding animations we have.
130      */
131     fun notifySurfaceReleased() {
132         surfaceBehind = null
133 
134         if (alphaAnimator.isRunning) {
135             alphaAnimator.cancel()
136         }
137 
138         if (translateYSpring.isRunning) {
139             translateYSpring.cancel()
140         }
141     }
142 
143     private fun startOrUpdateAnimators() {
144         if (surfaceBehind == null) {
145             return
146         }
147 
148         if (viewParams.willAnimateAlpha()) {
149             var fromAlpha = viewParams.animateFromAlpha
150 
151             if (alphaAnimator.isRunning) {
152                 alphaAnimator.cancel()
153                 fromAlpha = animatedAlpha
154             }
155 
156             alphaAnimator.setFloatValues(fromAlpha, viewParams.alpha)
157             alphaAnimator.start()
158         }
159 
160         if (viewParams.willAnimateTranslationY()) {
161             if (!translateYSpring.isRunning) {
162                 // If the spring isn't running yet, set the start value. Otherwise, respect the
163                 // current position.
164                 animatedTranslationY.value = viewParams.animateFromTranslationY
165                 translateYSpring.setStartVelocity(viewParams.startVelocity)
166             }
167 
168             translateYSpring.animateToFinalPosition(viewParams.translationY)
169         }
170 
171         updateIsAnimatingSurface()
172     }
173 
174     private fun updateIsAnimatingSurface() {
175         interactor.setAnimatingSurface(translateYSpring.isRunning || alphaAnimator.isRunning)
176     }
177 
178     private fun applyToSurfaceBehind() {
179         surfaceBehind?.leash?.let { sc ->
180             executor.execute {
181                 if (surfaceBehind == null) {
182                     Log.d(
183                         TAG,
184                         "Attempting to modify params of surface that isn't " +
185                             "animating. Ignoring."
186                     )
187                     matrix.set(Matrix.IDENTITY_MATRIX)
188                     return@execute
189                 }
190 
191                 val translationY =
192                     if (translateYSpring.isRunning) animatedTranslationY.value
193                     else viewParams.translationY
194 
195                 val alpha =
196                     if (alphaAnimator.isRunning) {
197                         animatedAlpha
198                     } else {
199                         viewParams.alpha
200                     }
201 
202                 if (
203                     keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE &&
204                         sc.isValid
205                 ) {
206                     with(SurfaceControl.Transaction()) {
207                         setMatrix(
208                             sc,
209                             matrix.apply { setTranslate(/* dx= */ 0f, translationY) },
210                             tmpFloat
211                         )
212                         setAlpha(sc, alpha)
213                         apply()
214                     }
215                 } else {
216                     surfaceTransactionApplier.scheduleApply(
217                         SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(sc)
218                             .withMatrix(matrix.apply { setTranslate(/* dx= */ 0f, translationY) })
219                             .withAlpha(alpha)
220                             .build()
221                     )
222                 }
223             }
224         }
225     }
226 }
227