• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 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.wm.shell.desktopmode
18 
19 import android.animation.Animator
20 import android.animation.RectEvaluator
21 import android.animation.ValueAnimator
22 import android.graphics.Rect
23 import android.view.SurfaceControl
24 import androidx.core.animation.addListener
25 import com.android.internal.jank.Cuj
26 import com.android.internal.jank.InteractionJankMonitor
27 import com.android.wm.shell.windowdecor.OnTaskRepositionAnimationListener
28 import java.util.function.Supplier
29 
30 /** Animates the task surface moving from its current drag position to its pre-drag position. */
31 class ReturnToDragStartAnimator(
32     private val transactionSupplier: Supplier<SurfaceControl.Transaction>,
33     private val interactionJankMonitor: InteractionJankMonitor,
34 ) {
35     private var boundsAnimator: Animator? = null
36     private lateinit var taskRepositionAnimationListener: OnTaskRepositionAnimationListener
37 
38     constructor(
39         interactionJankMonitor: InteractionJankMonitor
40     ) : this(Supplier { SurfaceControl.Transaction() }, interactionJankMonitor)
41 
42     /** Sets a listener for the start and end of the reposition animation. */
43     fun setTaskRepositionAnimationListener(listener: OnTaskRepositionAnimationListener) {
44         taskRepositionAnimationListener = listener
45     }
46 
47     /** Builds new animator and starts animation of task leash reposition. */
48     fun start(
49         taskId: Int,
50         taskSurface: SurfaceControl,
51         startBounds: Rect,
52         endBounds: Rect,
53         doOnEnd: (() -> Unit)? = null,
54     ) {
55         val tx = transactionSupplier.get()
56 
57         boundsAnimator?.cancel()
58         boundsAnimator =
59             ValueAnimator.ofObject(RectEvaluator(), startBounds, endBounds)
60                 .setDuration(RETURN_TO_DRAG_START_ANIMATION_MS)
61                 .apply {
62                     addListener(
63                         onStart = {
64                             val startTransaction = transactionSupplier.get()
65                             startTransaction
66                                 .setPosition(
67                                     taskSurface,
68                                     startBounds.left.toFloat(),
69                                     startBounds.top.toFloat(),
70                                 )
71                                 .show(taskSurface)
72                                 .apply()
73                             taskRepositionAnimationListener.onAnimationStart(taskId)
74                         },
75                         onEnd = {
76                             val finishTransaction = transactionSupplier.get()
77                             finishTransaction
78                                 .setPosition(
79                                     taskSurface,
80                                     endBounds.left.toFloat(),
81                                     endBounds.top.toFloat(),
82                                 )
83                                 .show(taskSurface)
84                                 .apply()
85                             taskRepositionAnimationListener.onAnimationEnd(taskId)
86                             boundsAnimator = null
87                             doOnEnd?.invoke()
88                             interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE)
89                         },
90                     )
91                     addUpdateListener { anim ->
92                         val rect = anim.animatedValue as Rect
93                         tx.setPosition(taskSurface, rect.left.toFloat(), rect.top.toFloat())
94                             .show(taskSurface)
95                             .apply()
96                     }
97                 }
98                 .also(ValueAnimator::start)
99     }
100 
101     companion object {
102         const val RETURN_TO_DRAG_START_ANIMATION_MS = 300L
103     }
104 }
105