Loading packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +34 −8 Original line number Diff line number Diff line Loading @@ -70,6 +70,9 @@ 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. * * The animator continues to respond to layout changes until [stopAnimating] is called. * * Successive calls to this method override the previous settings ([interpolator] and Loading @@ -82,9 +85,16 @@ class ViewHierarchyAnimator { fun animate( rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION duration: Long = DEFAULT_DURATION, excludedViews: Set<View> = emptySet() ): Boolean { return animate(rootView, interpolator, duration, ephemeral = false) return animate( rootView, interpolator, duration, ephemeral = false, excludedViews = excludedViews ) } /** Loading @@ -95,16 +105,24 @@ class ViewHierarchyAnimator { fun animateNextUpdate( rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION duration: Long = DEFAULT_DURATION, excludedViews: Set<View> = emptySet() ): Boolean { return animate(rootView, interpolator, duration, ephemeral = true) return animate( rootView, interpolator, duration, ephemeral = true, excludedViews = excludedViews ) } private fun animate( rootView: View, interpolator: Interpolator, duration: Long, ephemeral: Boolean ephemeral: Boolean, excludedViews: Set<View> = emptySet() ): Boolean { if ( !occupiesSpace( Loading @@ -119,7 +137,7 @@ class ViewHierarchyAnimator { } val listener = createUpdateListener(interpolator, duration, ephemeral) addListener(rootView, listener, recursive = true) addListener(rootView, listener, recursive = true, excludedViews = excludedViews) return true } Loading Loading @@ -921,8 +939,11 @@ class ViewHierarchyAnimator { private fun addListener( view: View, listener: View.OnLayoutChangeListener, recursive: Boolean = false recursive: Boolean = false, excludedViews: Set<View> = emptySet() ) { if (excludedViews.contains(view)) return // Make sure that only one listener is active at a time. val previousListener = view.getTag(R.id.tag_layout_listener) if (previousListener != null && previousListener is View.OnLayoutChangeListener) { Loading @@ -933,7 +954,12 @@ class ViewHierarchyAnimator { view.setTag(R.id.tag_layout_listener, listener) if (view is ViewGroup && recursive) { for (i in 0 until view.childCount) { addListener(view.getChildAt(i), listener, recursive = true) addListener( view.getChildAt(i), listener, recursive = true, excludedViews = excludedViews ) } } } Loading packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +36 −2 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import android.view.ViewGroup import android.widget.LinearLayout import android.widget.RelativeLayout import androidx.test.filters.SmallTest import com.android.app.animation.Interpolators import com.android.systemui.SysuiTestCase import com.android.systemui.util.children import junit.framework.Assert.assertEquals Loading @@ -19,7 +20,6 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import com.android.app.animation.Interpolators @SmallTest @RunWith(AndroidTestingRunner::class) Loading Loading @@ -178,7 +178,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test fun animatesRootAndChildren() { fun animatesRootAndChildren_withoutExcludedViews() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate(rootView) Loading Loading @@ -207,6 +207,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { checkBounds(rootView.getChildAt(1), l = 95, t = 0, r = 190, b = 100) } @Test fun animatesRootAndChildren_withExcludedViews() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate( rootView, excludedViews = setOf(rootView.getChildAt(0)) ) // 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)) assertNotNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) // The initial values for the affected views should be those of the previous layout, while // the excluded view 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 = 100, t = 0, r = 200, 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 +34 −8 Original line number Diff line number Diff line Loading @@ -70,6 +70,9 @@ 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. * * The animator continues to respond to layout changes until [stopAnimating] is called. * * Successive calls to this method override the previous settings ([interpolator] and Loading @@ -82,9 +85,16 @@ class ViewHierarchyAnimator { fun animate( rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION duration: Long = DEFAULT_DURATION, excludedViews: Set<View> = emptySet() ): Boolean { return animate(rootView, interpolator, duration, ephemeral = false) return animate( rootView, interpolator, duration, ephemeral = false, excludedViews = excludedViews ) } /** Loading @@ -95,16 +105,24 @@ class ViewHierarchyAnimator { fun animateNextUpdate( rootView: View, interpolator: Interpolator = DEFAULT_INTERPOLATOR, duration: Long = DEFAULT_DURATION duration: Long = DEFAULT_DURATION, excludedViews: Set<View> = emptySet() ): Boolean { return animate(rootView, interpolator, duration, ephemeral = true) return animate( rootView, interpolator, duration, ephemeral = true, excludedViews = excludedViews ) } private fun animate( rootView: View, interpolator: Interpolator, duration: Long, ephemeral: Boolean ephemeral: Boolean, excludedViews: Set<View> = emptySet() ): Boolean { if ( !occupiesSpace( Loading @@ -119,7 +137,7 @@ class ViewHierarchyAnimator { } val listener = createUpdateListener(interpolator, duration, ephemeral) addListener(rootView, listener, recursive = true) addListener(rootView, listener, recursive = true, excludedViews = excludedViews) return true } Loading Loading @@ -921,8 +939,11 @@ class ViewHierarchyAnimator { private fun addListener( view: View, listener: View.OnLayoutChangeListener, recursive: Boolean = false recursive: Boolean = false, excludedViews: Set<View> = emptySet() ) { if (excludedViews.contains(view)) return // Make sure that only one listener is active at a time. val previousListener = view.getTag(R.id.tag_layout_listener) if (previousListener != null && previousListener is View.OnLayoutChangeListener) { Loading @@ -933,7 +954,12 @@ class ViewHierarchyAnimator { view.setTag(R.id.tag_layout_listener, listener) if (view is ViewGroup && recursive) { for (i in 0 until view.childCount) { addListener(view.getChildAt(i), listener, recursive = true) addListener( view.getChildAt(i), listener, recursive = true, excludedViews = excludedViews ) } } } Loading
packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +36 −2 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import android.view.ViewGroup import android.widget.LinearLayout import android.widget.RelativeLayout import androidx.test.filters.SmallTest import com.android.app.animation.Interpolators import com.android.systemui.SysuiTestCase import com.android.systemui.util.children import junit.framework.Assert.assertEquals Loading @@ -19,7 +20,6 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import com.android.app.animation.Interpolators @SmallTest @RunWith(AndroidTestingRunner::class) Loading Loading @@ -178,7 +178,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test fun animatesRootAndChildren() { fun animatesRootAndChildren_withoutExcludedViews() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate(rootView) Loading Loading @@ -207,6 +207,40 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { checkBounds(rootView.getChildAt(1), l = 95, t = 0, r = 190, b = 100) } @Test fun animatesRootAndChildren_withExcludedViews() { setUpRootWithChildren() val success = ViewHierarchyAnimator.animate( rootView, excludedViews = setOf(rootView.getChildAt(0)) ) // 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)) assertNotNull(rootView.getChildAt(1).getTag(R.id.tag_animator)) // The initial values for the affected views should be those of the previous layout, while // the excluded view 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 = 100, t = 0, r = 200, 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