Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +27 −14 Original line number Diff line number Diff line Loading @@ -470,15 +470,8 @@ public class StackStateAnimator { mHeadsUpAppearChildren.add(changingView); mTmpState.copyFrom(changingView.getViewState()); if (event.headsUpFromBottom) { // start from the bottom of the screen mTmpState.setYTranslation( mHeadsUpAppearHeightBottom + mHeadsUpAppearStartAboveScreen); } else { // start from the top of the screen mTmpState.setYTranslation( -mStackTopMargin - mHeadsUpAppearStartAboveScreen); } // translate the HUN in from the top, or the bottom of the screen mTmpState.setYTranslation(getHeadsUpYTranslationStart(event.headsUpFromBottom)); // set the height and the initial position mTmpState.applyToView(changingView); mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y, Loading Loading @@ -522,12 +515,20 @@ public class StackStateAnimator { || event.animationType == ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) { mHeadsUpDisappearChildren.add(changingView); Runnable endRunnable = null; mTmpState.copyFrom(changingView.getViewState()); if (changingView.getParent() == null) { // This notification was actually removed, so we need to add it // transiently mHostLayout.addTransientView(changingView, 0); changingView.setTransientContainer(mHostLayout); mTmpState.initFrom(changingView); if (NotificationsImprovedHunAnimation.isEnabled()) { // StackScrollAlgorithm cannot find this view because it has been removed // from the NSSL. To correctly translate the view to the top or bottom of // the screen (where it animated from), we need to update its translation. mTmpState.setYTranslation( getHeadsUpYTranslationStart(event.headsUpFromBottom) ); } endRunnable = changingView::removeFromTransientContainer; } Loading Loading @@ -575,16 +576,19 @@ public class StackStateAnimator { changingView.setInRemovalAnimation(true); }; } if (NotificationsImprovedHunAnimation.isEnabled()) { mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y, Interpolators.FAST_OUT_SLOW_IN_REVERSE); } long removeAnimationDelay = changingView.performRemoveAnimation( ANIMATION_DURATION_HEADS_UP_DISAPPEAR, 0, 0.0f, true /* isHeadsUpAppear */, startAnimation, postAnimation, getGlobalAnimationFinishedListener()); mAnimationProperties.delay += removeAnimationDelay; if (NotificationsImprovedHunAnimation.isEnabled()) { mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR; mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y, Interpolators.FAST_OUT_SLOW_IN_REVERSE); mAnimationProperties.getAnimationFilter().animateY = true; mTmpState.animateTo(changingView, mAnimationProperties); } } else if (endRunnable != null) { endRunnable.run(); } Loading @@ -595,6 +599,15 @@ public class StackStateAnimator { return needsCustomAnimation; } private float getHeadsUpYTranslationStart(boolean headsUpFromBottom) { if (headsUpFromBottom) { // start from the bottom of the screen return mHeadsUpAppearHeightBottom + mHeadsUpAppearStartAboveScreen; } // start from the top of the screen return -mStackTopMargin - mHeadsUpAppearStartAboveScreen; } public void animateOverScrollToAmount(float targetAmount, final boolean onTop, final boolean isRubberbanded) { final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt +15 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ package com.android.systemui.statusbar.notification.stack import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.res.R import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation Loading @@ -31,10 +33,12 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mockito.any import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.description import org.mockito.Mockito.eq import org.mockito.Mockito.verify Loading @@ -45,8 +49,11 @@ private const val HEADS_UP_ABOVE_SCREEN = 80 @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper class StackStateAnimatorTest : SysuiTestCase() { @get:Rule val animatorTestRule = AnimatorTestRule(this) private lateinit var stackStateAnimator: StackStateAnimator private val stackScroller: NotificationStackScrollLayout = mock() private val view: ExpandableView = mock() Loading Loading @@ -112,13 +119,16 @@ class StackStateAnimatorTest : SysuiTestCase() { } @Test @EnableFlags(NotificationsImprovedHunAnimation.FLAG_NAME) fun startAnimationForEvents_startsHeadsUpDisappearAnim() { val disappearDuration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong() val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) clearInvocations(view) stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0) verify(view) .performRemoveAnimation( /* duration= */ eq(ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong()), /* duration= */ eq(disappearDuration), /* delay= */ eq(0L), /* translationDirection= */ eq(0f), /* isHeadsUpAnimation= */ eq(true), Loading @@ -127,9 +137,12 @@ class StackStateAnimatorTest : SysuiTestCase() { /* animationListener= */ any() ) animatorTestRule.advanceTimeBy(disappearDuration) // move to the end of SSA animations runnableCaptor.value.run() // execute the end runnable verify(view, description("should be called at the end of the animation")) verify(view, description("should be translated to the heads up appear start")) .translationY = -stackStateAnimator.mHeadsUpAppearStartAboveScreen verify(view, description("should be called at the end of the disappear animation")) .removeFromTransientContainer() } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +27 −14 Original line number Diff line number Diff line Loading @@ -470,15 +470,8 @@ public class StackStateAnimator { mHeadsUpAppearChildren.add(changingView); mTmpState.copyFrom(changingView.getViewState()); if (event.headsUpFromBottom) { // start from the bottom of the screen mTmpState.setYTranslation( mHeadsUpAppearHeightBottom + mHeadsUpAppearStartAboveScreen); } else { // start from the top of the screen mTmpState.setYTranslation( -mStackTopMargin - mHeadsUpAppearStartAboveScreen); } // translate the HUN in from the top, or the bottom of the screen mTmpState.setYTranslation(getHeadsUpYTranslationStart(event.headsUpFromBottom)); // set the height and the initial position mTmpState.applyToView(changingView); mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y, Loading Loading @@ -522,12 +515,20 @@ public class StackStateAnimator { || event.animationType == ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) { mHeadsUpDisappearChildren.add(changingView); Runnable endRunnable = null; mTmpState.copyFrom(changingView.getViewState()); if (changingView.getParent() == null) { // This notification was actually removed, so we need to add it // transiently mHostLayout.addTransientView(changingView, 0); changingView.setTransientContainer(mHostLayout); mTmpState.initFrom(changingView); if (NotificationsImprovedHunAnimation.isEnabled()) { // StackScrollAlgorithm cannot find this view because it has been removed // from the NSSL. To correctly translate the view to the top or bottom of // the screen (where it animated from), we need to update its translation. mTmpState.setYTranslation( getHeadsUpYTranslationStart(event.headsUpFromBottom) ); } endRunnable = changingView::removeFromTransientContainer; } Loading Loading @@ -575,16 +576,19 @@ public class StackStateAnimator { changingView.setInRemovalAnimation(true); }; } if (NotificationsImprovedHunAnimation.isEnabled()) { mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y, Interpolators.FAST_OUT_SLOW_IN_REVERSE); } long removeAnimationDelay = changingView.performRemoveAnimation( ANIMATION_DURATION_HEADS_UP_DISAPPEAR, 0, 0.0f, true /* isHeadsUpAppear */, startAnimation, postAnimation, getGlobalAnimationFinishedListener()); mAnimationProperties.delay += removeAnimationDelay; if (NotificationsImprovedHunAnimation.isEnabled()) { mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR; mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y, Interpolators.FAST_OUT_SLOW_IN_REVERSE); mAnimationProperties.getAnimationFilter().animateY = true; mTmpState.animateTo(changingView, mAnimationProperties); } } else if (endRunnable != null) { endRunnable.run(); } Loading @@ -595,6 +599,15 @@ public class StackStateAnimator { return needsCustomAnimation; } private float getHeadsUpYTranslationStart(boolean headsUpFromBottom) { if (headsUpFromBottom) { // start from the bottom of the screen return mHeadsUpAppearHeightBottom + mHeadsUpAppearStartAboveScreen; } // start from the top of the screen return -mStackTopMargin - mHeadsUpAppearStartAboveScreen; } public void animateOverScrollToAmount(float targetAmount, final boolean onTop, final boolean isRubberbanded) { final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt +15 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ package com.android.systemui.statusbar.notification.stack import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.res.R import com.android.systemui.statusbar.notification.row.ExpandableView import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation Loading @@ -31,10 +33,12 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mockito.any import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.description import org.mockito.Mockito.eq import org.mockito.Mockito.verify Loading @@ -45,8 +49,11 @@ private const val HEADS_UP_ABOVE_SCREEN = 80 @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper class StackStateAnimatorTest : SysuiTestCase() { @get:Rule val animatorTestRule = AnimatorTestRule(this) private lateinit var stackStateAnimator: StackStateAnimator private val stackScroller: NotificationStackScrollLayout = mock() private val view: ExpandableView = mock() Loading Loading @@ -112,13 +119,16 @@ class StackStateAnimatorTest : SysuiTestCase() { } @Test @EnableFlags(NotificationsImprovedHunAnimation.FLAG_NAME) fun startAnimationForEvents_startsHeadsUpDisappearAnim() { val disappearDuration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong() val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) clearInvocations(view) stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0) verify(view) .performRemoveAnimation( /* duration= */ eq(ANIMATION_DURATION_HEADS_UP_DISAPPEAR.toLong()), /* duration= */ eq(disappearDuration), /* delay= */ eq(0L), /* translationDirection= */ eq(0f), /* isHeadsUpAnimation= */ eq(true), Loading @@ -127,9 +137,12 @@ class StackStateAnimatorTest : SysuiTestCase() { /* animationListener= */ any() ) animatorTestRule.advanceTimeBy(disappearDuration) // move to the end of SSA animations runnableCaptor.value.run() // execute the end runnable verify(view, description("should be called at the end of the animation")) verify(view, description("should be translated to the heads up appear start")) .translationY = -stackStateAnimator.mHeadsUpAppearStartAboveScreen verify(view, description("should be called at the end of the disappear animation")) .removeFromTransientContainer() } Loading