From 0fd7190fdd0629bbcccc251e040feee41fa5be68 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Wed, 28 Dec 2016 14:15:03 -0800 Subject: [PATCH] Refine animation to remove strange reshuffling animation The issue happens mainly because two animations(move + change) running on the same view interrupt with each other. When ItemAnimator runs the move animation, it will change the translationX&Y in a time period. When the change animation occurs in this period, it gets this translation value and calculates a non-zero deta, then it would run an unnecessary move animation, which causes the strange reshuffling. In this cl, I skip the translation value only for the tile view when there is pending animation. I also add scroll operation for conditions view to make it scroll to top after condition change. Bug: 33839777 Bug: 33839780 Test: make -j40 RunSettingsRoboTests Change-Id: I2152f93f756ae20cf754d6fca3525119cb4ceb1f --- .../settings/dashboard/DashboardItemAnimator.java | 13 ++++++++++--- .../settings/dashboard/DashboardSummary.java | 1 + .../dashboard/DashboardItemAnimatorTest.java | 15 +++++++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/com/android/settings/dashboard/DashboardItemAnimator.java b/src/com/android/settings/dashboard/DashboardItemAnimator.java index fcaba227f7b..88e69e50baf 100644 --- a/src/com/android/settings/dashboard/DashboardItemAnimator.java +++ b/src/com/android/settings/dashboard/DashboardItemAnimator.java @@ -18,15 +18,22 @@ package com.android.settings.dashboard; import android.support.v4.view.ViewCompat; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.RecyclerView.ViewHolder; +import com.android.settingslib.drawer.Tile; public class DashboardItemAnimator extends DefaultItemAnimator { @Override public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { - if (oldHolder == newHolder) { - fromX += ViewCompat.getTranslationX(oldHolder.itemView); - fromY += ViewCompat.getTranslationY(oldHolder.itemView); + final Object tag = oldHolder.itemView.getTag(); + if (tag instanceof Tile && oldHolder == newHolder) { + // When this view has other move animation running, skip this value to avoid + // animations interrupt each other. + if (!isRunning()) { + fromX += ViewCompat.getTranslationX(oldHolder.itemView); + fromY += ViewCompat.getTranslationY(oldHolder.itemView); + } + if (fromX == toX && fromY == toY) { dispatchMoveFinished(oldHolder); return false; diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java index 136ccaf60ea..ebc9b525baf 100644 --- a/src/com/android/settings/dashboard/DashboardSummary.java +++ b/src/com/android/settings/dashboard/DashboardSummary.java @@ -263,6 +263,7 @@ public class DashboardSummary extends InstrumentedPreferenceFragment public void onConditionsChanged() { Log.d(TAG, "onConditionsChanged"); mAdapter.setConditions(mConditionManager.getConditions()); + mDashboard.scrollToPosition(0); } private class SuggestionLoader extends AsyncTask> { diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java index 6ca6f4d3e4a..90ff25c9f0c 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardItemAnimatorTest.java @@ -21,6 +21,7 @@ import android.widget.TextView; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.dashboard.SupportItemAdapter.ViewHolder; +import com.android.settingslib.drawer.Tile; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,20 +42,30 @@ public class DashboardItemAnimatorTest { final Context context = ShadowApplication.getInstance().getApplicationContext(); mDashboardItemAnimator = new DashboardItemAnimator(); mViewHolder = new ViewHolder(new TextView(context)); + mViewHolder.itemView.setTag(new Tile()); } @Test - public void testAnimateChange_NoOffset_NoPendingAnimation() { + public void testAnimateChange_NoPositionChange_NoPendingAnimation() { final boolean hasPendingAnimation = mDashboardItemAnimator .animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1); assertThat(hasPendingAnimation).isFalse(); } @Test - public void testAnimateChange_HasOffset_HasPendingAnimation() { + public void testAnimateChange_HasPositionChange_HasPendingAnimation() { final boolean hasPendingAnimation = mDashboardItemAnimator .animateChange(mViewHolder, mViewHolder, 0, 0, 1, 1); assertThat(hasPendingAnimation).isTrue(); } + @Test + public void testAnimateChange_HasRunningAnimationWhileNoPositionChange_NoPendingAnimation() { + // Set pending move animations + mDashboardItemAnimator.animateMove(mViewHolder, 0, 0, 1, 1); + + final boolean hasPendingAnimation = mDashboardItemAnimator + .animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1); + assertThat(hasPendingAnimation).isFalse(); + } }