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