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