1 /*
2  * 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 package com.android.wm.shell.back
17 
18 import android.content.Context
19 import android.view.SurfaceControl
20 import android.window.BackEvent
21 import com.android.wm.shell.R
22 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
23 import com.android.wm.shell.animation.Interpolators
24 import javax.inject.Inject
25 import kotlin.math.max
26 
27 /** Class that defines cross-activity animation. */
28 class DefaultCrossActivityBackAnimation
29 @Inject
30 constructor(
31     context: Context,
32     background: BackAnimationBackground,
33     rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
34 ) :
35     CrossActivityBackAnimation(
36         context,
37         background,
38         rootTaskDisplayAreaOrganizer,
39         SurfaceControl.Transaction()
40     ) {
41 
42     private val postCommitInterpolator = Interpolators.EMPHASIZED
43     private val enteringStartOffset =
44         context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset)
45     override val allowEnteringYShift = true
46 
preparePreCommitClosingRectMovementnull47     override fun preparePreCommitClosingRectMovement(swipeEdge: Int) {
48         startClosingRect.set(backAnimRect)
49 
50         // scale closing target into the middle for rhs and to the right for lhs
51         targetClosingRect.set(startClosingRect)
52         targetClosingRect.scaleCentered(MAX_SCALE)
53         if (swipeEdge != BackEvent.EDGE_RIGHT) {
54             targetClosingRect.offset(
55                     startClosingRect.right - targetClosingRect.right - displayBoundsMargin,
56                     0f
57             )
58         }
59     }
60 
preparePreCommitEnteringRectMovementnull61     override fun preparePreCommitEnteringRectMovement() {
62         // the entering target starts 96dp to the left of the screen edge...
63         startEnteringRect.set(startClosingRect)
64         startEnteringRect.offset(-enteringStartOffset, 0f)
65         // ...and gets scaled in sync with the closing target
66         targetEnteringRect.set(startEnteringRect)
67         targetEnteringRect.scaleCentered(MAX_SCALE)
68     }
69 
getPostCommitAnimationDurationnull70     override fun getPostCommitAnimationDuration() = POST_COMMIT_DURATION
71 
72     override fun onGestureCommitted(velocity: Float) {
73         // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
74         // coordinate of the gesture driven phase. Let's update the start and target rects and kick
75         // off the animator in the superclass
76         startClosingRect.set(currentClosingRect)
77         startEnteringRect.set(currentEnteringRect)
78         targetEnteringRect.set(backAnimRect)
79         targetClosingRect.set(backAnimRect)
80         targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
81         super.onGestureCommitted(velocity)
82     }
83 
onPostCommitProgressnull84     override fun onPostCommitProgress(linearProgress: Float) {
85         super.onPostCommitProgress(linearProgress)
86         val closingAlpha = max(1f - linearProgress * 5, 0f)
87         val progress = postCommitInterpolator.getInterpolation(linearProgress)
88         currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress)
89         applyTransform(
90             closingTarget?.leash,
91             currentClosingRect,
92             closingAlpha,
93             flingMode = FlingMode.FLING_BOUNCE
94         )
95         currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
96         applyTransform(
97             enteringTarget?.leash,
98             currentEnteringRect,
99             1f,
100             flingMode = FlingMode.FLING_BOUNCE
101         )
102         applyTransaction()
103     }
104 
105 
106     companion object {
107         private const val POST_COMMIT_DURATION = 450L
108     }
109 }
110