diff options
4 files changed, 86 insertions, 14 deletions
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt index cc7d23e97d0c..dc2c63561d79 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt @@ -165,6 +165,8 @@ class ViewHierarchyAnimator { * @param includeFadeIn true if the animator should also fade in the view and child views. * @param fadeInInterpolator the interpolator to use when fading in the view. Unused if * [includeFadeIn] is false. + * @param onAnimationEnd an optional runnable that will be run once the animation + * finishes successfully. Will not be run if the animation is cancelled. */ @JvmOverloads fun animateAddition( @@ -174,7 +176,8 @@ class ViewHierarchyAnimator { duration: Long = DEFAULT_DURATION, includeMargins: Boolean = false, includeFadeIn: Boolean = false, - fadeInInterpolator: Interpolator = DEFAULT_FADE_IN_INTERPOLATOR + fadeInInterpolator: Interpolator = DEFAULT_FADE_IN_INTERPOLATOR, + onAnimationEnd: Runnable? = null, ): Boolean { if ( occupiesSpace( @@ -193,7 +196,8 @@ class ViewHierarchyAnimator { origin, interpolator, duration, - ignorePreviousValues = !includeMargins + ignorePreviousValues = !includeMargins, + onAnimationEnd, ) addListener(rootView, listener, recursive = true) @@ -246,14 +250,16 @@ class ViewHierarchyAnimator { origin: Hotspot, interpolator: Interpolator, duration: Long, - ignorePreviousValues: Boolean + ignorePreviousValues: Boolean, + onAnimationEnd: Runnable? = null, ): View.OnLayoutChangeListener { return createListener( interpolator, duration, ephemeral = true, origin = origin, - ignorePreviousValues = ignorePreviousValues + ignorePreviousValues = ignorePreviousValues, + onAnimationEnd, ) } @@ -272,7 +278,8 @@ class ViewHierarchyAnimator { duration: Long, ephemeral: Boolean, origin: Hotspot? = null, - ignorePreviousValues: Boolean = false + ignorePreviousValues: Boolean = false, + onAnimationEnd: Runnable? = null, ): View.OnLayoutChangeListener { return object : View.OnLayoutChangeListener { override fun onLayoutChange( @@ -340,7 +347,8 @@ class ViewHierarchyAnimator { endValues, interpolator, duration, - ephemeral + ephemeral, + onAnimationEnd, ) } } @@ -903,7 +911,8 @@ class ViewHierarchyAnimator { endValues: Map<Bound, Int>, interpolator: Interpolator, duration: Long, - ephemeral: Boolean + ephemeral: Boolean, + onAnimationEnd: Runnable? = null, ) { val propertyValuesHolders = buildList { @@ -941,6 +950,9 @@ class ViewHierarchyAnimator { // listener. recursivelyRemoveListener(view) } + if (!cancelled) { + onAnimationEnd?.run() + } } override fun onAnimationCancel(animation: Animator?) { diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt index 9ab83b84277e..2278938c398e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt @@ -56,7 +56,7 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>( internal val logger: MediaTttLogger, internal val windowManager: WindowManager, private val viewUtil: ViewUtil, - @Main internal val mainExecutor: DelayableExecutor, + @Main private val mainExecutor: DelayableExecutor, private val accessibilityManager: AccessibilityManager, private val configurationController: ConfigurationController, private val powerManager: PowerManager, diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index 92d9ea89fce2..933548963390 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -160,12 +160,8 @@ class MediaTttChipControllerSender @Inject constructor( duration = ANIMATION_DURATION, includeMargins = true, includeFadeIn = true, - ) - - // We can only request focus once the animation finishes. - mainExecutor.executeDelayed( - { chipInnerView.requestAccessibilityFocus() }, - ANIMATION_DURATION + // We can only request focus once the animation finishes. + onAnimationEnd = { chipInnerView.requestAccessibilityFocus() }, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt index 273786d74782..8fc048920ea7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt @@ -664,6 +664,60 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test + fun animateAddition_runnableRunsWhenAnimationEnds() { + var runnableRun = false + val onAnimationEndRunnable = { runnableRun = true } + + ViewHierarchyAnimator.animateAddition( + rootView, + origin = ViewHierarchyAnimator.Hotspot.CENTER, + includeMargins = true, + onAnimationEnd = onAnimationEndRunnable + ) + rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */) + + endAnimation(rootView) + + assertEquals(true, runnableRun) + } + + @Test + fun animateAddition_runnableDoesNotRunWhenAnimationCancelled() { + var runnableRun = false + val onAnimationEndRunnable = { runnableRun = true } + + ViewHierarchyAnimator.animateAddition( + rootView, + origin = ViewHierarchyAnimator.Hotspot.CENTER, + includeMargins = true, + onAnimationEnd = onAnimationEndRunnable + ) + rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */) + + cancelAnimation(rootView) + + assertEquals(false, runnableRun) + } + + @Test + fun animationAddition_runnableDoesNotRunWhenOnlyPartwayThroughAnimation() { + var runnableRun = false + val onAnimationEndRunnable = { runnableRun = true } + + ViewHierarchyAnimator.animateAddition( + rootView, + origin = ViewHierarchyAnimator.Hotspot.CENTER, + includeMargins = true, + onAnimationEnd = onAnimationEndRunnable + ) + rootView.layout(50 /* l */, 50 /* t */, 100 /* r */, 100 /* b */) + + advanceAnimation(rootView, 0.5f) + + assertEquals(false, runnableRun) + } + + @Test fun animatesViewRemovalFromStartToEnd() { setUpRootWithChildren() @@ -1158,6 +1212,16 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } } + private fun cancelAnimation(rootView: View) { + (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel() + + if (rootView is ViewGroup) { + for (i in 0 until rootView.childCount) { + cancelAnimation(rootView.getChildAt(i)) + } + } + } + private fun endFadeInAnimation(rootView: View) { (rootView.getTag(R.id.tag_alpha_animator) as? ObjectAnimator)?.end() |