Merge "Fixing crash when filtering tasks too quickly."

This commit is contained in:
Winson Chung
2014-04-04 17:22:07 +00:00
committed by Android (Google) Code Review
9 changed files with 270 additions and 81 deletions

View File

@@ -107,5 +107,10 @@
<!-- milliseconds before the heads up notification accepts touches. -->
<integer name="heads_up_sensitivity_delay">700</integer>
<!-- The min animation duration for animating views that are currently visible. -->
<integer name="recents_filter_animate_current_views_min_duration">175</integer>
<!-- The min animation duration for animating views that are newly visible. -->
<integer name="recents_filter_animate_new_views_min_duration">125</integer>
</resources>

View File

@@ -236,6 +236,10 @@
<!-- The size of the activity icon in the recents task view. -->
<dimen name="recents_task_view_activity_icon_size">60dp</dimen>
<!-- Used to calculate the translation animation duration, the expected amount of movement
in dps over one second of time. -->
<dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
<!-- Space below the notification stack -->
<dimen name="notification_stack_margin_bottom">0dp</dimen>

View File

@@ -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]);
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);
}
AnimatorSet childViewAnimSet = new AnimatorSet();
childViewAnimSet.setDuration(
Constants.Values.TaskStackView.Animation.UnfilteredCurrentViewsDuration);
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 : 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;

View File

@@ -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();