1 package com.android.wm.shell.windowdecor
2 
3 import android.animation.ValueAnimator
4 import android.app.ActivityManager.RunningTaskInfo
5 import android.graphics.PointF
6 import android.graphics.Rect
7 import android.view.MotionEvent
8 import android.view.SurfaceControl
9 
10 /**
11  * Creates an animator to shrink and position task after a user drags a fullscreen task from
12  * the top of the screen to transition it into freeform and before the user releases the task. The
13  * MoveToDesktopAnimator object also holds information about the state of the task that are
14  * accessed by the EnterDesktopTaskTransitionHandler.
15  */
16 class MoveToDesktopAnimator @JvmOverloads constructor(
17         private val startBounds: Rect,
18         private val taskInfo: RunningTaskInfo,
19         private val taskSurface: SurfaceControl,
20         private val transactionFactory: () -> SurfaceControl.Transaction =
21                 SurfaceControl::Transaction
22 ) {
23     companion object {
24         // The size of the screen during drag relative to the fullscreen size
25         const val DRAG_FREEFORM_SCALE: Float = 0.4f
26         const val ANIMATION_DURATION = 336
27     }
28 
29     private val animatedTaskWidth
30         get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width()
31     private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f,
32             DRAG_FREEFORM_SCALE)
33             .setDuration(ANIMATION_DURATION.toLong())
34             .apply {
35                 val t = SurfaceControl.Transaction()
36                 addUpdateListener { animation ->
37                     val animatorValue = animation.animatedValue as Float
38                     t.setScale(taskSurface, animatorValue, animatorValue)
39                             .apply()
40                 }
41             }
42 
43     val taskId get() = taskInfo.taskId
44     val position: PointF = PointF(0.0f, 0.0f)
45 
46     /**
47      * Starts the animation that scales the task down.
48      */
49     fun startAnimation() {
50         dragToDesktopAnimator.start()
51     }
52 
53     /**
54      * Uses the position of the motion event and the current scale of the task as defined by the
55      * ValueAnimator to update the local position variable and set the task surface's position
56      */
57     fun updatePosition(ev: MotionEvent) {
58         position.x = ev.x - animatedTaskWidth / 2
59         position.y = ev.y
60 
61         val t = transactionFactory()
62         t.setPosition(taskSurface, position.x, position.y)
63         t.apply()
64     }
65 
66     /**
67      * Ends the animation, setting the scale and position to the final animation value
68      */
69     fun endAnimator() {
70         dragToDesktopAnimator.end()
71     }
72 }