Loading packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +19 −4 Original line number Diff line number Diff line Loading @@ -70,8 +70,10 @@ class ViewHierarchyAnimator { * If a new layout change happens while an animation is already in progress, the animation * is updated to continue from the current values to the new end state. * * A set of [excludedViews] can be passed. If any dependent view from [rootView] matches an * entry in this set, changes to that view will not be animated. * By default, child views whole layout changes are animated as well. However, this can be * controlled by [animateChildren]. If children are included, a set of [excludedViews] can * be passed. If any dependent view from [rootView] matches an entry in this set, changes to * that view will not be animated. * * The animator continues to respond to layout changes until [stopAnimating] is called. * Loading @@ -86,6 +88,7 @@ class ViewHierarchyAnimator { rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION, animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ): Boolean { return animate( Loading @@ -93,6 +96,7 @@ class ViewHierarchyAnimator { interpolator, duration, ephemeral = false, animateChildren = animateChildren, excludedViews = excludedViews ) } Loading @@ -106,6 +110,7 @@ class ViewHierarchyAnimator { rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION, animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ): Boolean { return animate( Loading @@ -113,6 +118,7 @@ class ViewHierarchyAnimator { interpolator, duration, ephemeral = true, animateChildren = animateChildren, excludedViews = excludedViews ) } Loading @@ -122,6 +128,7 @@ class ViewHierarchyAnimator { interpolator: Interpolator, duration: Long, ephemeral: Boolean, animateChildren: Boolean, excludedViews: Set<View> = emptySet() ): Boolean { if ( Loading @@ -137,7 +144,13 @@ class ViewHierarchyAnimator { } val listener = createUpdateListener(interpolator, duration, ephemeral) addListener(rootView, listener, recursive = true, excludedViews = excludedViews) addListener( rootView, listener, recursive = true, animateChildren = animateChildren, excludedViews = excludedViews ) return true } Loading Loading @@ -940,6 +953,7 @@ class ViewHierarchyAnimator { view: View, listener: View.OnLayoutChangeListener, recursive: Boolean = false, animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ) { if (excludedViews.contains(view)) return Loading @@ -952,12 +966,13 @@ class ViewHierarchyAnimator { view.addOnLayoutChangeListener(listener) view.setTag(R.id.tag_layout_listener, listener) if (view is ViewGroup && recursive) { if (animateChildren && view is ViewGroup && recursive) { for (i in 0 until view.childCount) { addListener( view.getChildAt(i), listener, recursive = true, animateChildren = animateChildren, excludedViews = excludedViews ) } Loading packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +34 −0 Original line number Diff line number Diff line Loading @@ -241,6 +241,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) } @Test fun animatesRootOnly() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate( rootView, animateChildren = false ) // Change all bounds. rootView.measure( View.MeasureSpec.makeMeasureSpec(180, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY) ) rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */) assertTrue(success) assertNotNull(rootView.getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) // The initial values for the root view should be those of the previous layout, while the // children views should be at the final values from the beginning. checkBounds(rootView, l = 0, t = 0, r = 200, b = 100) checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) endAnimation(rootView) assertNull(rootView.getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) // The end values should be those of the latest layout. checkBounds(rootView, l = 10, t = 20, r = 200, b = 120) checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) } @Test fun animatesInvisibleViews() { rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */) Loading Loading
packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +19 −4 Original line number Diff line number Diff line Loading @@ -70,8 +70,10 @@ class ViewHierarchyAnimator { * If a new layout change happens while an animation is already in progress, the animation * is updated to continue from the current values to the new end state. * * A set of [excludedViews] can be passed. If any dependent view from [rootView] matches an * entry in this set, changes to that view will not be animated. * By default, child views whole layout changes are animated as well. However, this can be * controlled by [animateChildren]. If children are included, a set of [excludedViews] can * be passed. If any dependent view from [rootView] matches an entry in this set, changes to * that view will not be animated. * * The animator continues to respond to layout changes until [stopAnimating] is called. * Loading @@ -86,6 +88,7 @@ class ViewHierarchyAnimator { rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION, animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ): Boolean { return animate( Loading @@ -93,6 +96,7 @@ class ViewHierarchyAnimator { interpolator, duration, ephemeral = false, animateChildren = animateChildren, excludedViews = excludedViews ) } Loading @@ -106,6 +110,7 @@ class ViewHierarchyAnimator { rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION, animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ): Boolean { return animate( Loading @@ -113,6 +118,7 @@ class ViewHierarchyAnimator { interpolator, duration, ephemeral = true, animateChildren = animateChildren, excludedViews = excludedViews ) } Loading @@ -122,6 +128,7 @@ class ViewHierarchyAnimator { interpolator: Interpolator, duration: Long, ephemeral: Boolean, animateChildren: Boolean, excludedViews: Set<View> = emptySet() ): Boolean { if ( Loading @@ -137,7 +144,13 @@ class ViewHierarchyAnimator { } val listener = createUpdateListener(interpolator, duration, ephemeral) addListener(rootView, listener, recursive = true, excludedViews = excludedViews) addListener( rootView, listener, recursive = true, animateChildren = animateChildren, excludedViews = excludedViews ) return true } Loading Loading @@ -940,6 +953,7 @@ class ViewHierarchyAnimator { view: View, listener: View.OnLayoutChangeListener, recursive: Boolean = false, animateChildren: Boolean = true, excludedViews: Set<View> = emptySet() ) { if (excludedViews.contains(view)) return Loading @@ -952,12 +966,13 @@ class ViewHierarchyAnimator { view.addOnLayoutChangeListener(listener) view.setTag(R.id.tag_layout_listener, listener) if (view is ViewGroup && recursive) { if (animateChildren && view is ViewGroup && recursive) { for (i in 0 until view.childCount) { addListener( view.getChildAt(i), listener, recursive = true, animateChildren = animateChildren, excludedViews = excludedViews ) } Loading
packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +34 −0 Original line number Diff line number Diff line Loading @@ -241,6 +241,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) } @Test fun animatesRootOnly() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate( rootView, animateChildren = false ) // Change all bounds. rootView.measure( View.MeasureSpec.makeMeasureSpec(180, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY) ) rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */) assertTrue(success) assertNotNull(rootView.getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) // The initial values for the root view should be those of the previous layout, while the // children views should be at the final values from the beginning. checkBounds(rootView, l = 0, t = 0, r = 200, b = 100) checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) endAnimation(rootView) assertNull(rootView.getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator)) assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) // The end values should be those of the latest layout. checkBounds(rootView, l = 10, t = 20, r = 200, b = 120) checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 90, b = 100) checkBounds(rootView.getChildAt(1), l = 90, t = 0, r = 180, b = 100) } @Test fun animatesInvisibleViews() { rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */) Loading