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 package com.android.quickstep.util 17 18 import android.animation.TimeInterpolator 19 import android.animation.ValueAnimator 20 import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME 21 import android.graphics.Rect 22 import android.os.IBinder 23 import android.os.RemoteException 24 import android.view.SurfaceControl 25 import android.view.SurfaceControl.Transaction 26 import android.window.IRemoteTransitionFinishedCallback 27 import android.window.RemoteTransitionStub 28 import android.window.TransitionInfo 29 import com.android.launcher3.anim.AnimatorListeners.forEndCallback 30 import com.android.launcher3.util.Executors 31 import com.android.wm.shell.shared.TransitionUtil 32 33 /** Remote animation which slides the opening targets in and the closing targets out */ 34 class SlideInRemoteTransition( 35 private val isRtl: Boolean, 36 private val pageSpacing: Int, 37 private val cornerRadius: Float, 38 private val interpolator: TimeInterpolator, 39 private val onStartCallback: Runnable, 40 private val onFinishCallback: Runnable, 41 ) : RemoteTransitionStub() { 42 private val animationDurationMs = 500L 43 startAnimationnull44 override fun startAnimation( 45 transition: IBinder, 46 info: TransitionInfo, 47 startT: Transaction, 48 finishCB: IRemoteTransitionFinishedCallback 49 ) { 50 val anim = ValueAnimator.ofFloat(0f, 1f) 51 anim.interpolator = interpolator 52 anim.duration = animationDurationMs 53 54 val closingStartBounds: HashMap<SurfaceControl, Rect> = HashMap() 55 val openingEndBounds: HashMap<SurfaceControl, Rect> = HashMap() 56 for (chg in info.changes) { 57 val leash = chg.leash 58 startT.show(leash) 59 60 val taskInfo = chg.taskInfo 61 if (taskInfo?.activityType == ACTIVITY_TYPE_HOME || taskInfo?.parentTaskId != -1) { 62 continue 63 } 64 if (TransitionUtil.isClosingType(chg.mode)) { 65 closingStartBounds[leash] = chg.startAbsBounds 66 startT.setCrop(leash, chg.startAbsBounds).setCornerRadius(leash, cornerRadius) 67 } 68 if (TransitionUtil.isOpeningType(chg.mode)) { 69 openingEndBounds[leash] = chg.endAbsBounds 70 startT.setCrop(leash, chg.endAbsBounds).setCornerRadius(leash, cornerRadius) 71 } 72 } 73 onStartCallback.run() 74 startT.apply() 75 76 anim.addUpdateListener { 77 val t = Transaction() 78 closingStartBounds.keys.forEach { 79 // Translate the surface from its original position on-screen to off-screen on the 80 // right (or left in RTL) 81 val startBounds = closingStartBounds[it] 82 val targetX = (if (isRtl) -1 else 1) * (startBounds!!.right + pageSpacing) 83 t.setPosition(it, anim.animatedValue as Float * targetX, 0f) 84 } 85 openingEndBounds.keys.forEach { 86 // Set the alpha in the update listener to prevent one visible frame at the 87 // beginning 88 t.setAlpha(it, 1f) 89 // Translate the surface from off-screen on the left (or left in RTL) to its final 90 // position on-screen 91 val endBounds = openingEndBounds[it] 92 val targetX = (if (isRtl) -1 else 1) * (endBounds!!.right + pageSpacing) 93 t.setPosition(it, (1f - anim.animatedValue as Float) * -targetX, 0f) 94 } 95 t.apply() 96 } 97 anim.addListener( 98 forEndCallback( 99 Runnable { 100 val t = Transaction() 101 try { 102 finishCB.onTransitionFinished(null, t) 103 onFinishCallback.run() 104 } catch (e: RemoteException) { 105 // Ignore 106 } 107 } 108 ) 109 ) 110 111 Executors.MAIN_EXECUTOR.execute { anim.start() } 112 } 113 } 114