• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.launcher3.taskbar
18 
19 import android.animation.Animator
20 import android.animation.AnimatorSet
21 import android.animation.ObjectAnimator
22 import android.animation.ValueAnimator
23 import android.content.Context
24 import android.view.View
25 import androidx.dynamicanimation.animation.SpringForce
26 import com.android.app.animation.Interpolators
27 import com.android.launcher3.LauncherAnimUtils
28 import com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X
29 import com.android.launcher3.anim.SpringAnimationBuilder
30 import com.android.wm.shell.shared.bubbles.BubbleBarLocation
31 
32 /** Animator helper that creates bars animators. */
33 object BarsLocationAnimatorHelper {
34     const val FADE_OUT_ANIM_ALPHA_DURATION_MS: Long = 50L
35     const val FADE_OUT_ANIM_ALPHA_DELAY_MS: Long = 50L
36     const val FADE_OUT_ANIM_POSITION_DURATION_MS: Long = 100L
37     const val FADE_IN_ANIM_ALPHA_DURATION_MS: Long = 100L
38 
39     // Use STIFFNESS_MEDIUMLOW which is not defined in the API constants
40     private const val FADE_IN_ANIM_POSITION_SPRING_STIFFNESS: Float = 400f
41 
42     // During fade out animation we shift the bubble bar 1/80th of the screen width
43     private const val FADE_OUT_ANIM_POSITION_SHIFT: Float = 1 / 80f
44 
45     // During fade in animation we shift the bubble bar 1/60th of the screen width
46     private const val FADE_IN_ANIM_POSITION_SHIFT: Float = 1 / 60f
47 
48     private val Context.screenWidth: Int
49         get() = resources.displayMetrics.widthPixels
50 
51     val Context.outShift: Float
52         get() = screenWidth * FADE_OUT_ANIM_POSITION_SHIFT
53 
54     val Context.inShiftX: Float
55         get() = screenWidth * FADE_IN_ANIM_POSITION_SHIFT
56 
57     /**
58      * Creates out animation for targetView that animates it finalTx and plays targetViewAlphaAnim
59      * to its final value.
60      */
createLocationOutAnimatornull61     private fun createLocationOutAnimator(
62         finalTx: Float,
63         targetViewAlphaAnim: ObjectAnimator,
64         targetView: View,
65     ): Animator {
66         val positionAnim =
67             ObjectAnimator.ofFloat(targetView, VIEW_TRANSLATE_X, finalTx)
68                 .setDuration(FADE_OUT_ANIM_POSITION_DURATION_MS)
69         positionAnim.interpolator = Interpolators.EMPHASIZED_ACCELERATE
70 
71         targetViewAlphaAnim.setDuration(FADE_OUT_ANIM_ALPHA_DURATION_MS)
72         targetViewAlphaAnim.startDelay = FADE_OUT_ANIM_ALPHA_DELAY_MS
73 
74         val animatorSet = AnimatorSet()
75         animatorSet.playTogether(positionAnim, targetViewAlphaAnim)
76         return animatorSet
77     }
78 
79     /**
80      * Creates in animation for targetView that animates it from startTx to finalTx and plays
81      * targetViewAlphaAnim to its final value.
82      */
createLocationInAnimatornull83     private fun createLocationInAnimator(
84         startTx: Float,
85         finalTx: Float,
86         targetViewAlphaAnim: ObjectAnimator,
87         targetView: View,
88     ): Animator {
89         targetViewAlphaAnim.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS)
90         val positionAnim: ValueAnimator =
91             SpringAnimationBuilder(targetView.context)
92                 .setStartValue(startTx)
93                 .setEndValue(finalTx)
94                 .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
95                 .setStiffness(FADE_IN_ANIM_POSITION_SPRING_STIFFNESS)
96                 .build(targetView, VIEW_TRANSLATE_X)
97         val animatorSet = AnimatorSet()
98         animatorSet.playTogether(positionAnim, targetViewAlphaAnim)
99         return animatorSet
100     }
101 
102     /** Creates an animator for the bubble bar view in part. */
103     @JvmStatic
getBubbleBarLocationInAnimatornull104     fun getBubbleBarLocationInAnimator(
105         newLocation: BubbleBarLocation,
106         currentLocation: BubbleBarLocation,
107         distanceFromOtherSide: Float,
108         targetViewAlphaAnim: ObjectAnimator,
109         bubbleBarView: View,
110     ): Animator {
111         val shift: Float = bubbleBarView.context.outShift
112 
113         val onLeft = newLocation.isOnLeft(bubbleBarView.isLayoutRtl)
114         val startTx: Float
115         val finalTx =
116             if (newLocation == currentLocation) {
117                 // Animated location matches layout location.
118                 0f
119             } else {
120                 // We are animating in to a transient location, need to move the bar
121                 // accordingly.
122                 distanceFromOtherSide * (if (onLeft) -1 else 1)
123             }
124         startTx =
125             if (onLeft) {
126                 // Bar will be shown on the left side. Start point is shifted right.
127                 finalTx + shift
128             } else {
129                 // Bar will be shown on the right side. Start point is shifted left.
130                 finalTx - shift
131             }
132         return createLocationInAnimator(startTx, finalTx, targetViewAlphaAnim, bubbleBarView)
133     }
134 
135     /**
136      * Creates an animator for the bubble bar view out part.
137      *
138      * @param targetLocation the location bubble bar should animate to.
139      */
140     @JvmStatic
getBubbleBarLocationOutAnimatornull141     fun getBubbleBarLocationOutAnimator(
142         bubbleBarView: View,
143         targetLocation: BubbleBarLocation,
144         targetViewAlphaAnim: ObjectAnimator,
145     ): Animator {
146         val onLeft = targetLocation.isOnLeft(bubbleBarView.isLayoutRtl)
147         val shift = bubbleBarView.context.outShift
148         val finalTx = bubbleBarView.translationX + (if (onLeft) -shift else shift)
149         return this.createLocationOutAnimator(finalTx, targetViewAlphaAnim, bubbleBarView)
150     }
151 
152     /** Creates a teleport animator for the navigation buttons view. */
153     @JvmStatic
getTeleportAnimatorForNavButtonsnull154     fun getTeleportAnimatorForNavButtons(
155         location: BubbleBarLocation,
156         navButtonsView: View,
157         navBarTargetTranslationX: Float,
158     ): Animator {
159         val outShift: Float = navButtonsView.context.outShift
160         val isNavBarOnRight: Boolean = location.isOnLeft(navButtonsView.isLayoutRtl)
161         val finalOutTx =
162             navButtonsView.translationX + (if (isNavBarOnRight) outShift else -outShift)
163         val fadeout: Animator =
164             createLocationOutAnimator(
165                 finalOutTx,
166                 ObjectAnimator.ofFloat(navButtonsView, LauncherAnimUtils.VIEW_ALPHA, 0f),
167                 navButtonsView,
168             )
169         val inShift: Float = navButtonsView.context.inShiftX
170         val inStartX = navBarTargetTranslationX + (if (isNavBarOnRight) -inShift else inShift)
171         val fadeIn: Animator =
172             createLocationInAnimator(
173                 inStartX,
174                 navBarTargetTranslationX,
175                 ObjectAnimator.ofFloat(navButtonsView, LauncherAnimUtils.VIEW_ALPHA, 1f),
176                 navButtonsView,
177             )
178         val teleportAnimator = AnimatorSet()
179         teleportAnimator.play(fadeout).before(fadeIn)
180         return teleportAnimator
181     }
182 }
183