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 ) : RemoteTransitionStub() { 40 private val animationDurationMs = 500L 41 startAnimationnull42 override fun startAnimation( 43 transition: IBinder, 44 info: TransitionInfo, 45 startT: Transaction, 46 finishCB: IRemoteTransitionFinishedCallback 47 ) { 48 val anim = ValueAnimator.ofFloat(0f, 1f) 49 anim.interpolator = interpolator 50 anim.duration = animationDurationMs 51 52 val closingStartBounds: HashMap<SurfaceControl, Rect> = HashMap() 53 val openingEndBounds: HashMap<SurfaceControl, Rect> = HashMap() 54 for (chg in info.changes) { 55 val leash = chg.leash 56 startT.show(leash) 57 58 val taskInfo = chg.taskInfo 59 if (taskInfo?.activityType == ACTIVITY_TYPE_HOME || taskInfo?.parentTaskId != -1) { 60 continue 61 } 62 if (TransitionUtil.isClosingType(chg.mode)) { 63 closingStartBounds[leash] = chg.startAbsBounds 64 startT.setCrop(leash, chg.startAbsBounds).setCornerRadius(leash, cornerRadius) 65 } 66 if (TransitionUtil.isOpeningType(chg.mode)) { 67 openingEndBounds[leash] = chg.endAbsBounds 68 startT.setCrop(leash, chg.endAbsBounds).setCornerRadius(leash, cornerRadius) 69 } 70 } 71 startT.apply() 72 73 anim.addUpdateListener { 74 val t = Transaction() 75 closingStartBounds.keys.forEach { 76 // Translate the surface from its original position on-screen to off-screen on the 77 // right (or left in RTL) 78 val startBounds = closingStartBounds[it] 79 val targetX = (if (isRtl) -1 else 1) * (startBounds!!.right + pageSpacing) 80 t.setPosition(it, anim.animatedValue as Float * targetX, 0f) 81 } 82 openingEndBounds.keys.forEach { 83 // Set the alpha in the update listener to prevent one visible frame at the 84 // beginning 85 t.setAlpha(it, 1f) 86 // Translate the surface from off-screen on the left (or left in RTL) to its final 87 // position on-screen 88 val endBounds = openingEndBounds[it] 89 val targetX = (if (isRtl) -1 else 1) * (endBounds!!.right + pageSpacing) 90 t.setPosition(it, (1f - anim.animatedValue as Float) * -targetX, 0f) 91 } 92 t.apply() 93 } 94 anim.addListener( 95 forEndCallback( 96 Runnable { 97 val t = Transaction() 98 try { 99 finishCB.onTransitionFinished(null, t) 100 } catch (e: RemoteException) { 101 // Ignore 102 } 103 } 104 ) 105 ) 106 107 Executors.MAIN_EXECUTOR.execute { anim.start() } 108 } 109 } 110