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