summaryrefslogtreecommitdiffstats
path: root/go/quickstep/src
diff options
context:
space:
mode:
authorKevin <kevhan@google.com>2019-04-10 14:04:43 -0700
committerKevin <kevhan@google.com>2019-04-23 09:26:52 -0700
commitfbe9182b7502df6ed8db0446130cdde53bc84095 (patch)
treeabc57303df8d3e032ef31e1f675022d4c73e16d3 /go/quickstep/src
parent6092a6ee1ef6a129525ab09acd008ce4d78add0a (diff)
downloadandroid_packages_apps_Trebuchet-fbe9182b7502df6ed8db0446130cdde53bc84095.tar.gz
android_packages_apps_Trebuchet-fbe9182b7502df6ed8db0446130cdde53bc84095.tar.bz2
android_packages_apps_Trebuchet-fbe9182b7502df6ed8db0446130cdde53bc84095.zip
Change layout anim from Animation => Animator
Change the layout animation to use animators instead of the built-in animation-based layout animation. Animator-based animations are more flexible and can act on the view properties themselves, making it easier to deal with if we need to cancel the animation later from a conflicting animation (i.e. we find out we need to animate a view out). Bug: 114136250 Test: Go to recents, see items animate in Change-Id: Id8227cd50e81999cac98912ac58cd2d6864c40af (cherry picked from commit 26ad999b10c35a28585ffd3a5928d90446379c95)
Diffstat (limited to 'go/quickstep/src')
-rw-r--r--go/quickstep/src/com/android/quickstep/views/IconRecentsView.java91
1 files changed, 71 insertions, 20 deletions
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index c06b6ec41..7f77b6cc4 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -24,14 +24,12 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.View;
import android.view.ViewDebug;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.LayoutAnimationController;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -40,6 +38,7 @@ import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
+import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener;
import com.android.launcher3.R;
import com.android.quickstep.RecentsToActivityHelper;
@@ -90,7 +89,6 @@ public final class IconRecentsView extends FrameLayout {
private final TaskListLoader mTaskLoader;
private final TaskAdapter mTaskAdapter;
private final TaskActionController mTaskActionController;
- private final LayoutAnimationController mLayoutAnimation;
private RecentsToActivityHelper mActivityHelper;
private RecyclerView mTaskRecyclerView;
@@ -98,6 +96,9 @@ public final class IconRecentsView extends FrameLayout {
private View mContentView;
private View mClearAllView;
private boolean mTransitionedFromApp;
+ private AnimatorSet mLayoutAnimation;
+ private final ArraySet<View> mLayingOutViews = new ArraySet<>();
+
public IconRecentsView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -106,7 +107,6 @@ public final class IconRecentsView extends FrameLayout {
mTaskAdapter = new TaskAdapter(mTaskLoader);
mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
mTaskAdapter.setActionController(mTaskActionController);
- mLayoutAnimation = createLayoutAnimation();
}
@Override
@@ -120,7 +120,20 @@ public final class IconRecentsView extends FrameLayout {
ItemTouchHelper helper = new ItemTouchHelper(
new TaskSwipeCallback(mTaskActionController));
helper.attachToRecyclerView(mTaskRecyclerView);
- mTaskRecyclerView.setLayoutAnimation(mLayoutAnimation);
+ mTaskRecyclerView.addOnChildAttachStateChangeListener(
+ new OnChildAttachStateChangeListener() {
+ @Override
+ public void onChildViewAttachedToWindow(@NonNull View view) {
+ if (mLayoutAnimation != null && !mLayingOutViews.contains(view)) {
+ // Child view was added that is not part of current layout animation
+ // so restart the animation.
+ animateFadeInLayoutAnimation();
+ }
+ }
+
+ @Override
+ public void onChildViewDetachedFromWindow(@NonNull View view) { }
+ });
mEmptyView = findViewById(R.id.recent_task_empty_view);
mContentView = findViewById(R.id.recent_task_content_view);
@@ -165,8 +178,7 @@ public final class IconRecentsView extends FrameLayout {
* becomes visible.
*/
public void onBeginTransitionToOverview() {
- mTaskRecyclerView.scheduleLayoutAnimation();
-
+ scheduleFadeInLayoutAnimation();
// Load any task changes
if (!mTaskLoader.needsToLoad()) {
return;
@@ -338,17 +350,56 @@ public final class IconRecentsView extends FrameLayout {
});
}
- private static LayoutAnimationController createLayoutAnimation() {
- AnimationSet anim = new AnimationSet(false /* shareInterpolator */);
-
- Animation alphaAnim = new AlphaAnimation(0, 1);
- alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION);
- anim.addAnimation(alphaAnim);
-
- LayoutAnimationController layoutAnim = new LayoutAnimationController(anim);
- layoutAnim.setDelay(
- (float) LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN / LAYOUT_ITEM_ANIMATE_IN_DURATION);
+ /**
+ * Schedule a one-shot layout animation on the next layout. Separate from
+ * {@link #scheduleLayoutAnimation()} as the animation is {@link Animator} based and acts on the
+ * view properties themselves, allowing more controllable behavior and making it easier to
+ * manage when the animation conflicts with another animation.
+ */
+ private void scheduleFadeInLayoutAnimation() {
+ ViewTreeObserver viewTreeObserver = mTaskRecyclerView.getViewTreeObserver();
+ viewTreeObserver.addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ animateFadeInLayoutAnimation();
+ viewTreeObserver.removeOnGlobalLayoutListener(this);
+ }
+ });
+ }
- return layoutAnim;
+ /**
+ * Start animating the layout animation where items fade in.
+ */
+ private void animateFadeInLayoutAnimation() {
+ if (mLayoutAnimation != null) {
+ // If layout animation still in progress, cancel and restart.
+ mLayoutAnimation.cancel();
+ }
+ TaskItemView[] views = getTaskViews();
+ int delay = 0;
+ mLayoutAnimation = new AnimatorSet();
+ for (TaskItemView view : views) {
+ view.setAlpha(0.0f);
+ Animator alphaAnim = ObjectAnimator.ofFloat(view, ALPHA, 0.0f, 1.0f);
+ alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION).setStartDelay(delay);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setAlpha(1.0f);
+ mLayingOutViews.remove(view);
+ }
+ });
+ delay += LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN;
+ mLayoutAnimation.play(alphaAnim);
+ mLayingOutViews.add(view);
+ }
+ mLayoutAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLayoutAnimation = null;
+ }
+ });
+ mLayoutAnimation.start();
}
}