[Taskbar icons unfold animation issue] Do not take into account initial translation
Removes taking into account initial translation in
move from center animation. Initially it was done
because in StatusBar items are aligned using translations
but we decided to use different approach there so it is
not necessary anymore.
Now move from center animator can only set translations
from positive/negative value when progress is 0 and sets
it to 0 when progress is 1 (previously it was 'capturing'
the initial translation and animated the translation to
its original value).
Taskbar icons are pre-aligned using translations when
user is on launcher. After several folds/unfolds these
translations were accumulating that led to incorrect
positioning of the icons.
Found one more issue that we didn't clear the animated
views list after finishing the animation in taskbar unfold
animation controller but it didn't affect the animation
itself.
Test: atest com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimatorTest
Test: unfold on launcher and use gesture nav to swipe to an app
Fixes: 199126683
Change-Id: I159313aae50a19bbef8c79f227dcae0d5463872d
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
index 915e7f6..e5933e6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
@@ -16,7 +16,6 @@
package com.android.systemui.shared.animation
import android.graphics.Point
-import android.util.MathUtils.lerp
import android.view.Surface
import android.view.View
import android.view.WindowManager
@@ -27,7 +26,7 @@
* Creates an animation where all registered views are moved into their final location
* by moving from the center of the screen to the sides
*/
-class UnfoldMoveFromCenterAnimator(
+class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
private val windowManager: WindowManager,
/**
* Allows to set custom translation applier
@@ -36,14 +35,13 @@
* using custom methods instead of [View.setTranslationX] or
* [View.setTranslationY]
*/
- var translationApplier: TranslationApplier = object : TranslationApplier {}
+ private val translationApplier: TranslationApplier = object : TranslationApplier {},
) : UnfoldTransitionProgressProvider.TransitionProgressListener {
private val screenSize = Point()
private var isVerticalFold = false
private val animatedViews: MutableList<AnimatedView> = arrayListOf()
- private val tmpArray = IntArray(2)
/**
* Updates display properties in order to calculate the initial position for the views
@@ -82,45 +80,52 @@
it.view.get()?.let { view ->
translationApplier.apply(
view = view,
- x = lerp(it.startTranslationX, it.finishTranslationX, progress),
- y = lerp(it.startTranslationY, it.finishTranslationY, progress)
+ x = it.startTranslationX * (1 - progress),
+ y = it.startTranslationY * (1 - progress)
)
}
}
}
private fun createAnimatedView(view: View): AnimatedView {
- val viewLocation = tmpArray
- view.getLocationOnScreen(viewLocation)
+ val viewCenter = getViewCenter(view)
+ val viewCenterX = viewCenter.x
+ val viewCenterY = viewCenter.y
- val viewX = viewLocation[0].toFloat()
- val viewY = viewLocation[1].toFloat()
-
- val viewCenterX = viewX + view.width / 2
- val viewCenterY = viewY + view.height / 2
-
- val translationXDiff: Float
- val translationYDiff: Float
+ val translationX: Float
+ val translationY: Float
if (isVerticalFold) {
val distanceFromScreenCenterToViewCenter = screenSize.x / 2 - viewCenterX
- translationXDiff = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
- translationYDiff = 0f
+ translationX = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
+ translationY = 0f
} else {
val distanceFromScreenCenterToViewCenter = screenSize.y / 2 - viewCenterY
- translationXDiff = 0f
- translationYDiff = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
+ translationX = 0f
+ translationY = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
}
return AnimatedView(
view = WeakReference(view),
- startTranslationX = view.translationX + translationXDiff,
- startTranslationY = view.translationY + translationYDiff,
- finishTranslationX = view.translationX,
- finishTranslationY = view.translationY
+ startTranslationX = translationX,
+ startTranslationY = translationY
)
}
+ private fun getViewCenter(view: View): Point {
+ val viewLocation = IntArray(2)
+ view.getLocationOnScreen(viewLocation)
+
+ val viewX = viewLocation[0]
+ val viewY = viewLocation[1]
+
+ val outPoint = Point()
+ outPoint.x = viewX + view.width / 2
+ outPoint.y = viewY + view.height / 2
+
+ return outPoint
+ }
+
/**
* Interface that allows to use custom logic to apply translation to view
*/
@@ -137,9 +142,7 @@
private class AnimatedView(
val view: WeakReference<View>,
val startTranslationX: Float,
- val startTranslationY: Float,
- val finishTranslationX: Float,
- val finishTranslationY: Float
+ val startTranslationY: Float
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
index a9c6a53..ebc6f2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
@@ -56,45 +56,71 @@
@Test
fun testRegisterViewOnTheLeftOfVerticalFold_halfProgress_viewTranslatedToTheRight() {
givenScreen(width = 100, height = 100, rotation = ROTATION_0)
- val view = createView(x = 20)
+ val view = createView(x = 20, width = 10, height = 10)
animator.registerViewForAnimation(view)
animator.onTransitionStarted()
animator.onTransitionProgress(0.5f)
// Positive translationX -> translated to the right
- assertThat(view.translationX).isWithin(0.1f).of(3.75f)
+ // 10x10 view center is 25px from the center,
+ // When progress is 0.5 it should be translated at:
+ // 25 * 0.3 * (1 - 0.5) = 3.75px
+ assertThat(view.translationX).isWithin(0.01f).of(3.75f)
}
@Test
fun testRegisterViewOnTheLeftOfVerticalFold_zeroProgress_viewTranslatedToTheRight() {
givenScreen(width = 100, height = 100, rotation = ROTATION_0)
- val view = createView(x = 20)
+ val view = createView(x = 20, width = 10, height = 10)
animator.registerViewForAnimation(view)
animator.onTransitionStarted()
animator.onTransitionProgress(0f)
// Positive translationX -> translated to the right
- assertThat(view.translationX).isWithin(0.1f).of(7.5f)
+ // 10x10 view center is 25px from the center,
+ // When progress is 0 it should be translated at:
+ // 25 * 0.3 * (1 - 0) = 7.5px
+ assertThat(view.translationX).isWithin(0.01f).of(7.5f)
}
@Test
fun testRegisterViewOnTheLeftOfVerticalFold_fullProgress_viewTranslatedToTheOriginalPosition() {
givenScreen(width = 100, height = 100, rotation = ROTATION_0)
- val view = createView(x = 20)
+ val view = createView(x = 20, width = 10, height = 10)
animator.registerViewForAnimation(view)
animator.onTransitionStarted()
animator.onTransitionProgress(1f)
+ // Positive translationX -> translated to the right
+ // 10x10 view center is 25px from the center,
+ // When progress is 1 it should be translated at:
+ // 25 * 0.3 * 0 = 0px
assertThat(view.translationX).isEqualTo(0f)
}
@Test
+ fun testViewOnTheLeftOfVerticalFoldWithTranslation_halfProgress_viewTranslatedToTheRight() {
+ givenScreen(width = 100, height = 100, rotation = ROTATION_0)
+ val view = createView(x = 20, width = 10, height = 10, translationX = 100f)
+ animator.registerViewForAnimation(view)
+ animator.onTransitionStarted()
+
+ animator.onTransitionProgress(0.5f)
+
+ // Positive translationX -> translated to the right, original translation is ignored
+ // 10x10 view center is 25px from the center,
+ // When progress is 0.5 it should be translated at:
+ // 25 * 0.3 * (1 - 0.5) = 3.75px
+ assertThat(view.translationX).isWithin(0.01f).of(3.75f)
+ }
+
+ @Test
fun testRegisterViewAndUnregister_halfProgress_viewIsNotUpdated() {
givenScreen(width = 100, height = 100, rotation = ROTATION_0)
- val view = createView(x = 20)
+ val view = createView(x = 20, width = 10, height = 10)
animator.registerViewForAnimation(view)
animator.onTransitionStarted()
animator.clearRegisteredViews()
@@ -107,7 +133,7 @@
@Test
fun testRegisterViewUpdateProgressAndUnregister_halfProgress_viewIsNotUpdated() {
givenScreen(width = 100, height = 100, rotation = ROTATION_0)
- val view = createView(x = 20)
+ val view = createView(x = 20, width = 10, height = 10)
animator.registerViewForAnimation(view)
animator.onTransitionStarted()
animator.onTransitionProgress(0.2f)
@@ -121,14 +147,14 @@
@Test
fun testRegisterViewOnTheTopOfHorizontalFold_halfProgress_viewTranslatedToTheBottom() {
givenScreen(width = 100, height = 100, rotation = ROTATION_90)
- val view = createView(y = 20)
+ val view = createView(y = 20, width = 10, height = 10)
animator.registerViewForAnimation(view)
animator.onTransitionStarted()
animator.onTransitionProgress(0.5f)
// Positive translationY -> translated to the bottom
- assertThat(view.translationY).isWithin(0.1f).of(3.75f)
+ assertThat(view.translationY).isWithin(0.01f).of(3.75f)
}
private fun createView(
@@ -156,9 +182,11 @@
}
}
- private fun givenScreen(width: Int = 100,
- height: Int = 100,
- rotation: Int = ROTATION_0) {
+ private fun givenScreen(
+ width: Int = 100,
+ height: Int = 100,
+ rotation: Int = ROTATION_0
+ ) {
val display = mock(Display::class.java)
whenever(display.getSize(any())).thenAnswer {
val size = (it.arguments[0] as Point)