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