Merge "Fixing crash when filtering tasks too quickly."
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user