diff options
author | Winson Chung <winsonc@google.com> | 2014-04-03 18:05:29 -0700 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2014-04-04 10:18:24 -0700 |
commit | 2f2ca08baa072376b3dfd60506625496aa05903f (patch) | |
tree | ecf3731fcc6cf5753744b8f72424360f222f82d4 /packages/SystemUI/src | |
parent | 5e3e5d8945249cfeb8bd59de112be88954ba62bf (diff) | |
download | frameworks_base-2f2ca08baa072376b3dfd60506625496aa05903f.zip frameworks_base-2f2ca08baa072376b3dfd60506625496aa05903f.tar.gz frameworks_base-2f2ca08baa072376b3dfd60506625496aa05903f.tar.bz2 |
Fixing crash when filtering tasks too quickly.
- Using a translation-based animation duration scheme
- Fixing issue where filtering a task could slide it out of view
Change-Id: Id434b4a98aa671d84d047dad18cbe26f543cdf25
Diffstat (limited to 'packages/SystemUI/src')
7 files changed, 261 insertions, 81 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java new file mode 100644 index 0000000..b085211 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java @@ -0,0 +1,67 @@ +package com.android.systemui.recents; + +import android.animation.TimeInterpolator; + +/** + * A pre-baked bezier-curved interpolator for quantum-paper transitions. + */ +public class BakedBezierInterpolator implements TimeInterpolator { + public static final BakedBezierInterpolator INSTANCE = new BakedBezierInterpolator(); + + /** + * Use the INSTANCE variable instead of instantiating. + */ + private BakedBezierInterpolator() { + super(); + } + + /** + * Lookup table values. + * Generated using a Bezier curve from (0,0) to (1,1) with control points: + * P0 (0,0) + * P1 (0.4, 0) + * P2 (0.2, 1.0) + * P3 (1.0, 1.0) + * + * Values sampled with x at regular intervals between 0 and 1. + * + * These values were generated using: + * ./scripts/bezier_interpolator_values_gen.py 0.4 0.2 + */ + private static final float[] VALUES = new float[] { + 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f, + 0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f, + 0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f, + 0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f, + 0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f, + 0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f, + 0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f, + 0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f, + 0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f, + 0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f + }; + + private static final float STEP_SIZE = 1.0f / (VALUES.length - 1); + + @Override + public float getInterpolation(float input) { + if (input >= 1.0f) { + return 1.0f; + } + + if (input <= 0f) { + return 0f; + } + + int position = Math.min( + (int)(input * (VALUES.length - 1)), + VALUES.length - 2); + + float quantized = position * STEP_SIZE; + float difference = input - quantized; + float weight = difference / STEP_SIZE; + + return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]); + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 8c5c8fa..86f188e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -34,7 +34,7 @@ public class Constants { // For debugging, this enables us to create mock recents tasks public static final boolean EnableSystemServicesProxy = false; // For debugging, this defines the number of mock recents packages to create - public static final int SystemServicesProxyMockPackageCount = 12; + public static final int SystemServicesProxyMockPackageCount = 3; // For debugging, this defines the number of mock recents tasks to create public static final int SystemServicesProxyMockTaskCount = 75; @@ -82,16 +82,8 @@ public class Constants { } public static class TaskStackView { - public static class Animation { - public static final int TaskRemovedReshuffleDuration = 200; - public static final int SnapScrollBackDuration = 650; - public static final int FilteredCurrentViewsDuration = 150; - public static final int FilteredNewViewsDuration = 200; - public static final int UnfilteredCurrentViewsDuration = 150; - public static final int UnfilteredNewViewsDuration = 200; - } - public static final int TaskStackOverscrollRange = 150; + public static final int FilterStartDelay = 25; // The padding will be applied to the smallest dimension, and then applied to all sides public static final float StackPaddingPct = 0.15f; @@ -106,12 +98,6 @@ public class Constants { } public static class TaskView { - public static class Animation { - public static final int TaskDataUpdatedFadeDuration = 250; - public static final int TaskIconOnEnterDuration = 175; - public static final int TaskIconOnLeavingDuration = 75; - } - public static final boolean AnimateFrontTaskIconOnEnterRecents = true; public static final boolean AnimateFrontTaskIconOnLeavingRecents = true; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 3d47cb6..5d58a09 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -17,11 +17,11 @@ package com.android.systemui.recents; import android.content.Context; -import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.util.DisplayMetrics; import android.util.TypedValue; +import com.android.systemui.R; /** A static Recents configuration for the current context @@ -34,6 +34,11 @@ public class RecentsConfiguration { public Rect systemInsets = new Rect(); public Rect displayRect = new Rect(); + public float animationDpsMovementPerSecond; + + public int filteringCurrentViewsMinAnimDuration; + public int filteringNewViewsMinAnimDuration; + /** Private constructor */ private RecentsConfiguration() {} @@ -58,6 +63,12 @@ public class RecentsConfiguration { mDisplayMetrics = dm; displayRect.set(0, 0, dm.widthPixels, dm.heightPixels); + animationDpsMovementPerSecond = + res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second); + filteringCurrentViewsMinAnimDuration = + res.getInteger(R.integer.recents_filter_animate_current_views_min_duration); + filteringNewViewsMinAnimDuration = + res.getInteger(R.integer.recents_filter_animate_new_views_min_duration); } public void updateSystemInsets(Rect insets) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index f147fbc..efcd948 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -51,9 +51,9 @@ public class SystemServicesProxy { if (Constants.DebugFlags.App.EnableSystemServicesProxy) { // Create a dummy icon - mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); + mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(mDummyIcon); - c.drawColor(0xFFFF0000); + c.drawColor(0xFF999999); c.setBitmap(null); } } @@ -77,7 +77,7 @@ public class SystemServicesProxy { rti.id = rti.persistentId = i; rti.baseIntent = new Intent(); rti.baseIntent.setComponent(cn); - rti.description = rti.activityLabel = + rti.description = rti.activityLabel = "" + i + " - " + Long.toString(Math.abs(new Random().nextLong()), 36); if (i % 2 == 0) { rti.activityIcon = Bitmap.createBitmap(mDummyIcon); @@ -118,7 +118,7 @@ public class SystemServicesProxy { if (Constants.DebugFlags.App.EnableSystemServicesProxy) { Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(thumbnail); - c.drawColor(0xFF00ff00); + c.drawColor(0xff333333); c.setBitmap(null); return thumbnail; } @@ -178,7 +178,7 @@ public class SystemServicesProxy { // If we are mocking, then return a mock label if (Constants.DebugFlags.App.EnableSystemServicesProxy) { - return new ColorDrawable(0xFFff0000); + return new ColorDrawable(0xFF666666); } return info.loadIcon(mPm); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java index 9048cba..9538ad0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java @@ -20,6 +20,19 @@ import android.graphics.Rect; /* Common code */ public class Utilities { + /** + * Calculates a consistent animation duration (ms) for all animations depending on the movement + * of the object being animated. + */ + public static int calculateTranslationAnimationDuration(int distancePx) { + return calculateTranslationAnimationDuration(distancePx, 100); + } + public static int calculateTranslationAnimationDuration(int distancePx, int minDuration) { + RecentsConfiguration config = RecentsConfiguration.getInstance(); + return Math.max(minDuration, + (int) (Math.abs(distancePx) / config.animationDpsMovementPerSecond) * 1000 /* ms/s */); + } + /** Scales a rect about its centroid */ public static void scaleRectAboutCenter(Rect r, float scale) { if (scale != 1.0f) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index dfd608c..fa06764 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -35,11 +35,11 @@ import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.OverScroller; import com.android.systemui.R; +import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsTaskLoader; -import com.android.systemui.recents.SystemServicesProxy; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -76,6 +76,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal OverScroller mScroller; ObjectAnimator mScrollAnimator; + // Filtering + AnimatorSet mFilterChildrenAnimator; + // Optimizations int mHwLayersRefCount; int mStackViewsAnimationDuration; @@ -180,7 +183,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal */ private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks, int stackScroll, - int[] visibleRangeOut) { + int[] visibleRangeOut, + boolean boundTranslationsToRect) { // XXX: Optimization: Use binary search to find the visible range ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>(); @@ -196,6 +200,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } lastVisibleIndex = i; } + + if (boundTranslationsToRect) { + transform.translationY = Math.min(transform.translationY, mRect.bottom); + } } if (visibleRangeOut != null) { visibleRangeOut[0] = firstVisibleIndex; @@ -219,7 +227,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int stackScroll = getStackScroll(); ArrayList<Task> tasks = mStack.getTasks(); ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll, - visibleRange); + visibleRange, false); // Update the visible state of all the tasks int taskCount = tasks.size(); @@ -286,7 +294,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** Animates the stack scroll into bounds */ - ObjectAnimator animateBoundScroll(int duration) { + ObjectAnimator animateBoundScroll() { int curScroll = getStackScroll(); int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll)); if (newScroll != curScroll) { @@ -298,16 +306,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal abortBoundScrollAnimation(); // Start a new scroll animation - animateScroll(curScroll, newScroll, duration); + animateScroll(curScroll, newScroll); mScrollAnimator.start(); } return mScrollAnimator; } /** Animates the stack scroll */ - void animateScroll(int curScroll, int newScroll, int duration) { + void animateScroll(int curScroll, int newScroll) { mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll); - mScrollAnimator.setDuration(duration); + mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll - + curScroll, 250)); + mScrollAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { @@ -625,7 +635,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } updateMinMaxScroll(true); - requestSynchronizeStackViewsWithModel(Constants.Values.TaskStackView.Animation.TaskRemovedReshuffleDuration); + int movement = (int) (Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height()); + requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement)); } @Override @@ -635,20 +646,22 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // (filtered) stack // XXX: Use HW Layers - // Stash the scroll for us to restore to when we unfilter + // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); // Compute the transforms of the items in the current stack final ArrayList<TaskViewTransform> curTaskTransforms = - getStackTransforms(curStack, mStashedScroll, null); + getStackTransforms(curStack, mStashedScroll, null, true); - // Bound the new stack scroll + // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better updateMinMaxScroll(false); + float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); + setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight)); boundScrollRaw(); - // Compute the transforms of the items in the new stack + // Compute the transforms of the items in the new stack after setting the new scroll final ArrayList<TaskViewTransform> taskTransforms = - getStackTransforms(mStack.getTasks(), getStackScroll(), null); + getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); // Animate all of the existing views on screen either out of view (if they are not visible // in the new stack) or to their final positions in the new stack @@ -656,13 +669,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal final ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Animator> childViewAnims = new ArrayList<Animator>(); int childCount = getChildCount(); + int movement = 0; for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); TaskViewTransform toTransform; int taskIndex = tasks.indexOf(task); - if ((taskIndex < 0) || !taskTransforms.get(taskIndex).visible) { - // Compose a new transform that animates the task view out of view + + boolean willBeInvisible = (taskIndex < 0) || !taskTransforms.get(taskIndex).visible; + if (willBeInvisible) { + // Compose a new transform that fades and slides the task out of view TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task)); toTransform = new TaskViewTransform(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); @@ -671,23 +687,49 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal childrenToReturnToPool.add(tv); } else { toTransform = taskTransforms.get(taskIndex); + + // Use the movement of the visible views to calculate the duration of the animation + movement = Math.max(movement, + Math.abs(toTransform.translationY - (int) tv.getTranslationY())); } childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform)); } - AnimatorSet childViewAnimSet = new AnimatorSet(); - childViewAnimSet.setDuration( - Constants.Values.TaskStackView.Animation.FilteredCurrentViewsDuration); - childViewAnimSet.addListener(new AnimatorListenerAdapter() { + // Cancel the previous animation + if (mFilterChildrenAnimator != null) { + mFilterChildrenAnimator.cancel(); + mFilterChildrenAnimator.removeAllListeners(); + } + + // Create a new animation for the existing children + final RecentsConfiguration config = RecentsConfiguration.getInstance(); + mFilterChildrenAnimator = new AnimatorSet(); + mFilterChildrenAnimator.setDuration( + Utilities.calculateTranslationAnimationDuration(movement, + config.filteringCurrentViewsMinAnimDuration)); + mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); + mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { + boolean isCancelled; + + @Override + public void onAnimationCancel(Animator animation) { + isCancelled = true; + } + @Override public void onAnimationEnd(Animator animation) { + if (isCancelled) return; + // Return all the removed children to the view pool for (TaskView tv : childrenToReturnToPool) { mViewPool.returnViewToPool(tv); } // For views that are not already visible, animate them in + ArrayList<Animator> newViewsAnims = new ArrayList<Animator>(); int taskCount = tasks.size(); + int movement = 0; + int offset = 0; for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); TaskViewTransform toTransform = taskTransforms.get(i); @@ -697,20 +739,38 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView tv = getChildViewForTask(task); if (tv == null) { tv = mViewPool.pickUpViewFromPool(task, task); + // Compose a new transform that fades and slides the new task in + fromTransform = new TaskViewTransform(toTransform); + tv.prepareTaskTransformForFilterTaskHidden(fromTransform); + tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); - // Animate from the current position to the new position - tv.prepareTaskTransformForFilterTaskVisible(fromTransform); - tv.updateViewPropertiesToTaskTransform(fromTransform, - toTransform, - Constants.Values.TaskStackView.Animation.FilteredNewViewsDuration); + Animator anim = tv.getAnimatorToTaskTransform(toTransform); + anim.setStartDelay(offset * + Constants.Values.TaskStackView.FilterStartDelay); + newViewsAnims.add(anim); + + // Use the movement of the newly visible views to calculate the duration + // of the animation + movement = Math.max(movement, Math.abs(toTransform.translationY - + fromTransform.translationY)); + offset++; } } + + // Animate the new views in + mFilterChildrenAnimator = new AnimatorSet(); + mFilterChildrenAnimator.setDuration( + Utilities.calculateTranslationAnimationDuration(movement, + config.filteringNewViewsMinAnimDuration)); + mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); + mFilterChildrenAnimator.playTogether(newViewsAnims); + mFilterChildrenAnimator.start(); } invalidate(); } }); - childViewAnimSet.playTogether(childViewAnims); - childViewAnimSet.start(); + mFilterChildrenAnimator.playTogether(childViewAnims); + mFilterChildrenAnimator.start(); } @Override @@ -718,16 +778,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Compute the transforms of the items in the current stack final int curScroll = getStackScroll(); final ArrayList<TaskViewTransform> curTaskTransforms = - getStackTransforms(curStack, curScroll, null); + getStackTransforms(curStack, curScroll, null, true); // Restore the stashed scroll updateMinMaxScroll(false); setStackScrollRaw(mStashedScroll); boundScrollRaw(); - // Compute the transforms of the items in the new stack + // Compute the transforms of the items in the new stack after restoring the stashed scroll final ArrayList<TaskViewTransform> taskTransforms = - getStackTransforms(mStack.getTasks(), getStackScroll(), null); + getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); // Animate all of the existing views out of view (if they are not in the visible range in // the new stack) or to their final positions in the new stack @@ -735,29 +795,55 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal final ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Animator> childViewAnims = new ArrayList<Animator>(); int childCount = getChildCount(); + int movement = 0; for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); int taskIndex = tasks.indexOf(task); - TaskViewTransform transform; + TaskViewTransform toTransform; // If the view is no longer visible, then we should just animate it out - if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) { - transform = new TaskViewTransform(curTaskTransforms.get(curStack.indexOf(task))); - tv.prepareTaskTransformForFilterTaskVisible(transform); + boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible; + if (willBeInvisible) { + toTransform = new TaskViewTransform(taskTransforms.get(taskIndex)); + tv.prepareTaskTransformForFilterTaskVisible(toTransform); childrenToRemove.add(tv); } else { - transform = taskTransforms.get(taskIndex); + toTransform = taskTransforms.get(taskIndex); + // Use the movement of the visible views to calculate the duration of the animation + movement = Math.max(movement, Math.abs(toTransform.translationY - + (int) tv.getTranslationY())); } - childViewAnims.add(tv.getAnimatorToTaskTransform(transform)); + + Animator anim = tv.getAnimatorToTaskTransform(toTransform); + childViewAnims.add(anim); + } + + // Cancel the previous animation + if (mFilterChildrenAnimator != null) { + mFilterChildrenAnimator.cancel(); + mFilterChildrenAnimator.removeAllListeners(); } - AnimatorSet childViewAnimSet = new AnimatorSet(); - childViewAnimSet.setDuration( - Constants.Values.TaskStackView.Animation.UnfilteredCurrentViewsDuration); - childViewAnimSet.addListener(new AnimatorListenerAdapter() { + // Create a new animation for the existing children + final RecentsConfiguration config = RecentsConfiguration.getInstance(); + mFilterChildrenAnimator = new AnimatorSet(); + mFilterChildrenAnimator.setDuration( + Utilities.calculateTranslationAnimationDuration(movement, + config.filteringCurrentViewsMinAnimDuration)); + mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); + mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { + boolean isCancelled; + + @Override + public void onAnimationCancel(Animator animation) { + isCancelled = true; + } + @Override public void onAnimationEnd(Animator animation) { + if (isCancelled) return; + // Return all the removed children to the view pool for (TaskView tv : childrenToRemove) { mViewPool.returnViewToPool(tv); @@ -768,8 +854,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // For views that are not already visible, animate them in ArrayList<Animator> newViewAnims = new ArrayList<Animator>(); - AnimatorSet newViewAnimSet = new AnimatorSet(); int taskCount = tasks.size(); + int movement = 0; int offset = 0; for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); @@ -780,34 +866,46 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // For views that are not already visible, animate them in tv = mViewPool.pickUpViewFromPool(task, task); - // Animate in this new view + // Compose a new transform to fade and slide the new task in TaskViewTransform fromTransform = new TaskViewTransform(toTransform); tv.prepareTaskTransformForFilterTaskHidden(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); - newViewAnims.add(tv.getAnimatorToTaskTransform(toTransform)); + + Animator anim = tv.getAnimatorToTaskTransform(toTransform); + anim.setStartDelay(offset * + Constants.Values.TaskStackView.FilterStartDelay); + newViewAnims.add(anim); + // Use the movement of the newly visible views to calculate the duration + // of the animation + movement = Math.max(movement, + Math.abs(toTransform.translationY - fromTransform.translationY)); offset++; } } } // Run the animation - newViewAnimSet.setDuration( - Constants.Values.TaskStackView.Animation.UnfilteredNewViewsDuration); - newViewAnimSet.playTogether(newViewAnims); - newViewAnimSet.addListener(new AnimatorListenerAdapter() { + mFilterChildrenAnimator = new AnimatorSet(); + mFilterChildrenAnimator.setDuration( + Utilities.calculateTranslationAnimationDuration(movement, + config.filteringNewViewsMinAnimDuration)); + mFilterChildrenAnimator.playTogether(newViewAnims); + mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // Decrement the hw layers ref count decHwLayersRefCount("unfilteredNewViews"); } }); - newViewAnimSet.start(); - + mFilterChildrenAnimator.start(); invalidate(); } }); - childViewAnimSet.playTogether(childViewAnims); - childViewAnimSet.start(); + mFilterChildrenAnimator.playTogether(childViewAnims); + mFilterChildrenAnimator.start(); + + // Clear the saved vars + mStashedScroll = 0; } /**** ViewPoolConsumer Implementation ****/ @@ -1056,7 +1154,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { // Animate the scroll back if we've cancelled - mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); + mSv.animateBoundScroll(); // Disable HW layers if (mIsScrolling) { mSv.decHwLayersRefCount("stackScroll"); @@ -1186,7 +1284,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { } else if (mSv.isScrollOutOfBounds()) { // Animate the scroll back into bounds // XXX: Make this animation a function of the velocity OR distance - mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); + mSv.animateBoundScroll(); } if (mIsScrolling) { @@ -1220,7 +1318,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { if (mSv.isScrollOutOfBounds()) { // Animate the scroll back into bounds // XXX: Make this animation a function of the velocity OR distance - mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); + mSv.animateBoundScroll(); } mActivePointerId = INACTIVE_POINTER_ID; mIsScrolling = false; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 2c27d44..e99fecb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -20,20 +20,24 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import com.android.systemui.R; +import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; +import java.util.Random; + /* A task view */ public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks { @@ -131,7 +135,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. .scaleY(toTransform.scale) .alpha(toTransform.alpha) .setDuration(duration) - .setInterpolator(new AccelerateDecelerateInterpolator()) + .setInterpolator(BakedBezierInterpolator.INSTANCE) .withLayer() .start(); } else { @@ -190,7 +194,8 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. .translationX(0) .translationY(0) .setStartDelay(235) - .setDuration(Constants.Values.TaskView.Animation.TaskIconOnEnterDuration) + .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setDuration(Utilities.calculateTranslationAnimationDuration(translate)) .withLayer() .start(); } @@ -206,8 +211,8 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. .translationX(translate / 2) .translationY(-translate) .setStartDelay(0) - .setDuration(Constants.Values.TaskView.Animation.TaskIconOnLeavingDuration) - .setInterpolator(new DecelerateInterpolator()) + .setInterpolator(BakedBezierInterpolator.INSTANCE) + .setDuration(Utilities.calculateTranslationAnimationDuration(translate)) .withLayer() .withEndAction(r) .start(); |