Loading packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt +30 −27 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -27,7 +26,7 @@ import java.lang.ref.WeakReference * 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 Loading @@ -36,14 +35,13 @@ class UnfoldMoveFromCenterAnimator( * 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 Loading Loading @@ -82,45 +80,52 @@ class UnfoldMoveFromCenterAnimator( 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 viewX = viewLocation[0].toFloat() val viewY = viewLocation[1].toFloat() val viewCenterX = viewX + view.width / 2 val viewCenterY = viewY + view.height / 2 val viewCenter = getViewCenter(view) val viewCenterX = viewCenter.x val viewCenterY = viewCenter.y 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 */ Loading @@ -137,9 +142,7 @@ class UnfoldMoveFromCenterAnimator( private class AnimatedView( val view: WeakReference<View>, val startTranslationX: Float, val startTranslationY: Float, val finishTranslationX: Float, val finishTranslationY: Float val startTranslationY: Float ) } Loading packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt +40 −12 Original line number Diff line number Diff line Loading @@ -56,45 +56,71 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { @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() Loading @@ -107,7 +133,7 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { @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) Loading @@ -121,14 +147,14 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { @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( Loading Loading @@ -156,9 +182,11 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { } } private fun givenScreen(width: Int = 100, private fun givenScreen( width: Int = 100, height: Int = 100, rotation: Int = ROTATION_0) { rotation: Int = ROTATION_0 ) { val display = mock(Display::class.java) whenever(display.getSize(any())).thenAnswer { val size = (it.arguments[0] as Point) Loading Loading
packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt +30 −27 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -27,7 +26,7 @@ import java.lang.ref.WeakReference * 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 Loading @@ -36,14 +35,13 @@ class UnfoldMoveFromCenterAnimator( * 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 Loading Loading @@ -82,45 +80,52 @@ class UnfoldMoveFromCenterAnimator( 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 viewX = viewLocation[0].toFloat() val viewY = viewLocation[1].toFloat() val viewCenterX = viewX + view.width / 2 val viewCenterY = viewY + view.height / 2 val viewCenter = getViewCenter(view) val viewCenterX = viewCenter.x val viewCenterY = viewCenter.y 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 */ Loading @@ -137,9 +142,7 @@ class UnfoldMoveFromCenterAnimator( private class AnimatedView( val view: WeakReference<View>, val startTranslationX: Float, val startTranslationY: Float, val finishTranslationX: Float, val finishTranslationY: Float val startTranslationY: Float ) } Loading
packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt +40 −12 Original line number Diff line number Diff line Loading @@ -56,45 +56,71 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { @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() Loading @@ -107,7 +133,7 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { @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) Loading @@ -121,14 +147,14 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { @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( Loading Loading @@ -156,9 +182,11 @@ class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() { } } private fun givenScreen(width: Int = 100, private fun givenScreen( width: Int = 100, height: Int = 100, rotation: Int = ROTATION_0) { rotation: Int = ROTATION_0 ) { val display = mock(Display::class.java) whenever(display.getSize(any())).thenAnswer { val size = (it.arguments[0] as Point) Loading