am 6ac3367d: Merge "Enabling filtering by base intent package."

* commit '6ac3367d5df999736470f29a2bbb623864f06d1a':
  Enabling filtering by base intent package.
This commit is contained in:
Winson Chung
2014-04-01 23:15:08 +00:00
committed by Android Git Automerger
12 changed files with 390 additions and 95 deletions

View File

@@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:background="#88000000">
android:background="#e6444444">
<ImageView
android:id="@+id/activity_icon"
android:layout_width="@dimen/recents_task_view_icon_size"

View File

@@ -26,7 +26,7 @@ public class Constants {
public static final boolean Verbose = false;
public static class App {
public static final boolean EnableTaskFiltering = false;
public static final boolean EnableTaskFiltering = true;
public static final boolean EnableTaskStackClipping = false;
public static final boolean EnableToggleNewRecentsActivity = false;
// This disables the bitmap and icon caches to
@@ -81,6 +81,10 @@ public class Constants {
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;
@@ -107,7 +111,7 @@ public class Constants {
public static final boolean AnimateFrontTaskIconOnEnterRecents = true;
public static final boolean AnimateFrontTaskIconOnLeavingRecents = true;
public static final boolean UseRoundedCorners = true;
public static final boolean UseRoundedCorners = false;
public static final float RoundedCornerRadiusDps = 3;
}
}

View File

@@ -54,8 +54,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
finish();
}
} else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// Dismiss recents and launch the first task if possible
dismissRecentsIfVisible();
// Try and unfilter and filtered stacks
if (!mRecentsView.unfilterFilteredStacks()) {
// If there are no filtered stacks, dismiss recents and launch the first task
dismissRecentsIfVisible();
}
}
}
};

View File

@@ -66,7 +66,7 @@ class SystemUIMessageHandler extends Handler {
// in a bottom inset
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
tsv.boundScroll();
TaskViewTransform transform = tsv.getStackTransform(0);
TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll());
Rect taskRect = new Rect(transform.rect);
data.putParcelable("taskRect", taskRect);

View File

@@ -190,7 +190,7 @@ class TaskResourceLoader implements Runnable {
// Load the icon
if (loadIcon == null || forceLoadTask) {
PackageManager pm = mContext.getPackageManager();
ActivityInfo info = pm.getActivityInfo(t.key.intent.getComponent(),
ActivityInfo info = pm.getActivityInfo(t.key.baseIntent.getComponent(),
PackageManager.GET_META_DATA);
Drawable icon = info.loadIcon(pm);
if (!mCancelled) {
@@ -218,7 +218,7 @@ class TaskResourceLoader implements Runnable {
} else {
Console.logError(mContext,
"Failed to load task top thumbnail for: " +
t.key.intent.getComponent().getPackageName());
t.key.baseIntent.getComponent().getPackageName());
}
}
}

View File

@@ -20,9 +20,6 @@ import android.graphics.Rect;
/* Common code */
public class Utilities {
public static final Rect tmpRect = new Rect();
public static final Rect tmpRect2 = new Rect();
/** Scales a rect about its centroid */
public static void scaleRectAboutCenter(Rect r, float scale) {
if (scale != 1.0f) {

View File

@@ -37,11 +37,11 @@ public class Task {
/* The Task Key represents the unique primary key for the task */
public static class TaskKey {
public final int id;
public final Intent intent;
public final Intent baseIntent;
public TaskKey(int id, Intent intent) {
this.id = id;
this.intent = intent;
this.baseIntent = intent;
}
@Override
@@ -56,7 +56,7 @@ public class Task {
@Override
public String toString() {
return "Task.Key: " + id + ", " + intent.getComponent().getPackageName();
return "Task.Key: " + id + ", " + baseIntent.getComponent().getPackageName();
}
}
@@ -120,6 +120,6 @@ public class Task {
@Override
public String toString() {
return "Task: " + key.intent.getComponent().getPackageName() + " [" + super.toString() + "]";
return "Task: " + key.baseIntent.getComponent().getPackageName() + " [" + super.toString() + "]";
}
}

View File

@@ -39,9 +39,11 @@ class FilteredTaskList {
TaskFilter mFilter;
/** Sets the task filter, saving the current touch state */
void setFilter(TaskFilter filter) {
boolean setFilter(TaskFilter filter) {
ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
mFilter = filter;
updateFilteredTasks();
return !prevFilteredTasks.equals(mFilteredTasks);
}
/** Removes the task filter and returns the previous touch state */
@@ -126,9 +128,9 @@ public class TaskStack {
/* Notifies when a task has been removed from the stack */
public void onStackTaskRemoved(TaskStack stack, Task t);
/** Notifies when the stack was filtered */
public void onStackFiltered(TaskStack stack);
public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
/** Notifies when the stack was un-filtered */
public void onStackUnfiltered(TaskStack stack);
public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
}
Context mContext;
@@ -201,29 +203,30 @@ public class TaskStack {
}
/** Filters the stack into tasks similar to the one specified */
public void filterTasks(Task t) {
public void filterTasks(final Task t) {
ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
// Set the task list filter
// XXX: This is a dummy filter that currently just accepts every other task.
mTaskList.setFilter(new TaskFilter() {
boolean filtered = mTaskList.setFilter(new TaskFilter() {
@Override
public boolean acceptTask(Task t, int i) {
if (i % 2 == 0) {
return true;
}
return false;
public boolean acceptTask(Task at, int i) {
return t.key.baseIntent.getComponent().getPackageName().equals(
at.key.baseIntent.getComponent().getPackageName());
}
});
if (mCb != null) {
mCb.onStackFiltered(this);
if (filtered && mCb != null) {
mCb.onStackFiltered(this, oldStack, t);
}
}
/** Unfilters the current stack */
public void unfilterTasks() {
ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
// Unset the filter, then update the virtual scroll
mTaskList.removeFilter();
if (mCb != null) {
mCb.onStackUnfiltered(this);
mCb.onStackUnfiltered(this, oldStack);
}
}

View File

@@ -211,17 +211,18 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
View sourceView = tv;
int offsetX = 0;
int offsetY = 0;
int stackScroll = stackView.getStackScroll();
if (tv == null) {
// If there is no actual task view, then use the stack view as the source view
// and then offset to the expected transform rect, but bound this to just
// outside the display rect (to ensure we don't animate from too far away)
RecentsConfiguration config = RecentsConfiguration.getInstance();
sourceView = stackView;
transform = stackView.getStackTransform(stack.indexOfTask(task));
transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
offsetX = transform.rect.left;
offsetY = Math.min(transform.rect.top, config.displayRect.height());
} else {
transform = stackView.getStackTransform(stack.indexOfTask(task));
transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
}
// Compute the thumbnail to scale up from
@@ -255,7 +256,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
} else {
// Launch the activity with the desired animation
Intent i = new Intent(task.key.intent);
Intent i = new Intent(task.key.baseIntent);
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);

View File

@@ -18,6 +18,7 @@ package com.android.systemui.recents.views;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -34,6 +35,7 @@ import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.OverScroller;
import com.android.systemui.R;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -41,7 +43,6 @@ import com.android.systemui.recents.RecentsTaskLoader;
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.R;
import java.util.ArrayList;
@@ -71,6 +72,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int mStackScroll;
int mMinScroll;
int mMaxScroll;
int mStashedScroll;
OverScroller mScroller;
ObjectAnimator mScrollAnimator;
@@ -79,6 +81,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int mStackViewsAnimationDuration;
boolean mStackViewsDirty = true;
boolean mAwaitingFirstLayout = true;
int[] mTmpVisibleRange = new int[2];
Rect mTmpRect = new Rect();
Rect mTmpRect2 = new Rect();
LayoutInflater mInflater;
public TaskStackView(Context context, TaskStack stack) {
@@ -102,7 +107,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
void requestSynchronizeStackViewsWithModel(int duration) {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|requestSynchronize]", "", Console.AnsiYellow);
"[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
if (!mStackViewsDirty) {
invalidate();
}
@@ -128,14 +133,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
/** Update/get the transform */
public TaskViewTransform getStackTransform(int indexInStack) {
public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) {
TaskViewTransform transform = new TaskViewTransform();
// Map the items to an continuous position relative to the current scroll
// Return early if we have an invalid index
if (indexInStack < 0) return transform;
// Map the items to an continuous position relative to the specified scroll
int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards;
float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
float peekHeight = Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
float t = ((indexInStack * overlapHeight) - getStackScroll()) / overlapHeight;
float t = ((indexInStack * overlapHeight) - stackScroll) / overlapHeight;
float boundedT = Math.max(t, -(numPeekCards + 1));
// Set the scale relative to its position
@@ -167,25 +175,57 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return transform;
}
/**
* Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
*/
private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
int stackScroll,
int[] visibleRangeOut) {
// XXX: Optimization: Use binary search to find the visible range
ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
int taskCount = tasks.size();
int firstVisibleIndex = -1;
int lastVisibleIndex = -1;
for (int i = 0; i < taskCount; i++) {
TaskViewTransform transform = getStackTransform(i, stackScroll);
taskTransforms.add(transform);
if (transform.visible) {
if (firstVisibleIndex < 0) {
firstVisibleIndex = i;
}
lastVisibleIndex = i;
}
}
if (visibleRangeOut != null) {
visibleRangeOut[0] = firstVisibleIndex;
visibleRangeOut[1] = lastVisibleIndex;
}
return taskTransforms;
}
/** Synchronizes the views with the model */
void synchronizeStackViewsWithModel() {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|synchronizeViewsWithModel]",
"mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
if (mStackViewsDirty) {
// XXX: Optimization: Use binary search to find the visible range
// XXX: Optimize to not call getStackTransform() so many times
// XXX: Consider using TaskViewTransform pool to prevent allocations
// XXX: Iterate children views, update transforms and remove all that are not visible
// For all remaining tasks, update transforms and if visible add the view
// Update the visible state of all the tasks
// Get all the task transforms
int[] visibleRange = mTmpVisibleRange;
int stackScroll = getStackScroll();
ArrayList<Task> tasks = mStack.getTasks();
ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll,
visibleRange);
// Update the visible state of all the tasks
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
TaskViewTransform transform = getStackTransform(i);
TaskViewTransform transform = taskTransforms.get(i);
TaskView tv = getChildViewForTask(task);
if (transform.visible) {
@@ -194,11 +234,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// When we are picking up a new view from the view pool, prepare it for any
// following animation by putting it in a reasonable place
if (mStackViewsAnimationDuration > 0 && i != 0) {
// XXX: We have to animate when filtering, etc. Maybe we should have a
// runnable that ensures that tasks are animated in a special way
// when they are entering the scene?
int fromIndex = (transform.t < 0) ? (i - 1) : (i + 1);
tv.updateViewPropertiesFromTask(null, getStackTransform(fromIndex), 0);
tv.updateViewPropertiesToTaskTransform(null,
getStackTransform(fromIndex, stackScroll), 0);
}
}
} else {
@@ -208,17 +246,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
}
// Update all the current view children
// Update all the remaining view children
// NOTE: We have to iterate in reverse where because we are removing views directly
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
TaskView tv = (TaskView) getChildAt(i);
Task task = tv.getTask();
TaskViewTransform transform = getStackTransform(mStack.indexOfTask(task));
if (!transform.visible) {
int taskIndex = mStack.indexOfTask(task);
if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
mViewPool.returnViewToPool(tv);
} else {
tv.updateViewPropertiesFromTask(null, transform, mStackViewsAnimationDuration);
tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex),
mStackViewsAnimationDuration);
}
}
@@ -235,6 +274,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mStackScroll = value;
requestSynchronizeStackViewsWithModel();
}
/** Sets the current stack scroll without synchronizing the stack view with the model */
public void setStackScrollRaw(int value) {
mStackScroll = value;
}
/** Gets the current stack scroll */
public int getStackScroll() {
@@ -251,36 +294,39 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Abort any current animations
abortScroller();
if (mScrollAnimator != null) {
mScrollAnimator.cancel();
mScrollAnimator.removeAllListeners();
}
abortBoundScrollAnimation();
// Start a new scroll animation
mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
mScrollAnimator.setDuration(duration);
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setStackScroll((Integer) animation.getAnimatedValue());
}
});
mScrollAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Disable hw layers on the stack
decHwLayersRefCount("animateBoundScroll");
}
});
animateScroll(curScroll, newScroll, duration);
mScrollAnimator.start();
}
return mScrollAnimator;
}
/** Animates the stack scroll */
void animateScroll(int curScroll, int newScroll, int duration) {
mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
mScrollAnimator.setDuration(duration);
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setStackScroll((Integer) animation.getAnimatedValue());
}
});
mScrollAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Disable hw layers on the stack
decHwLayersRefCount("animateBoundScroll");
}
});
}
/** Aborts any current stack scrolls */
void abortBoundScrollAnimation() {
if (mScrollAnimator != null) {
mScrollAnimator.cancel();
mScrollAnimator.removeAllListeners();
}
}
@@ -304,6 +350,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return false;
}
/**
* Bounds the current scroll if necessary, but does not synchronize the stack view with the
* model.
*/
public boolean boundScrollRaw() {
int curScroll = getStackScroll();
int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll));
if (newScroll != curScroll) {
setStackScrollRaw(newScroll);
return true;
}
return false;
}
/** Returns whether the current scroll is out of bounds */
boolean isScrollOutOfBounds() {
return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
@@ -404,12 +464,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskView tv = (TaskView) child;
TaskView nextTv = null;
int curIndex = indexOfChild(tv);
if (curIndex < (getChildCount() - 1)) {
if ((curIndex > -1) && (curIndex < (getChildCount() - 1))) {
// Clip against the next view (if we aren't animating its alpha)
nextTv = (TaskView) getChildAt(curIndex + 1);
if (nextTv.getAlpha() == 1f) {
Rect curRect = tv.getClippingRect(Utilities.tmpRect, false);
Rect nextRect = nextTv.getClippingRect(Utilities.tmpRect2, true);
Rect curRect = tv.getClippingRect(mTmpRect, false);
Rect nextRect = nextTv.getClippingRect(mTmpRect2, true);
RecentsConfiguration config = RecentsConfiguration.getInstance();
// The hit rects are relative to the task view, which needs to be offset by the
// system bar height
@@ -528,9 +588,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mTaskRect.right, mStackRectSansPeek.top + mTaskRect.height());
}
if (!mAwaitingFirstLayout) {
requestSynchronizeStackViewsWithModel();
} else {
if (mAwaitingFirstLayout) {
mAwaitingFirstLayout = false;
}
}
@@ -570,13 +628,185 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
@Override
public void onStackFiltered(TaskStack stack) {
requestSynchronizeStackViewsWithModel();
public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack,
Task filteredTask) {
// NOTE: This code assumes that the current (unfiltered) stack is a superset of the new
// (filtered) stack
// XXX: Use HW Layers
// Stash the scroll 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);
// Bound the new stack scroll
updateMinMaxScroll(false);
boundScrollRaw();
// Compute the transforms of the items in the new stack
final ArrayList<TaskViewTransform> taskTransforms =
getStackTransforms(mStack.getTasks(), getStackScroll(), null);
// 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
final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>();
final ArrayList<Task> tasks = mStack.getTasks();
ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
int childCount = getChildCount();
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
TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task));
toTransform = new TaskViewTransform(fromTransform);
tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
tv.prepareTaskTransformForFilterTaskHidden(toTransform);
childrenToReturnToPool.add(tv);
} else {
toTransform = taskTransforms.get(taskIndex);
}
childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
}
AnimatorSet childViewAnimSet = new AnimatorSet();
childViewAnimSet.setDuration(
Constants.Values.TaskStackView.Animation.FilteredCurrentViewsDuration);
childViewAnimSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// 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
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
TaskViewTransform toTransform = taskTransforms.get(i);
if (toTransform.visible) {
TaskViewTransform fromTransform =
curTaskTransforms.get(curStack.indexOf(task));
TaskView tv = getChildViewForTask(task);
if (tv == null) {
tv = mViewPool.pickUpViewFromPool(task, task);
// Animate from the current position to the new position
tv.prepareTaskTransformForFilterTaskVisible(fromTransform);
tv.updateViewPropertiesToTaskTransform(fromTransform,
toTransform,
Constants.Values.TaskStackView.Animation.FilteredNewViewsDuration);
}
}
}
invalidate();
}
});
childViewAnimSet.playTogether(childViewAnims);
childViewAnimSet.start();
}
@Override
public void onStackUnfiltered(TaskStack stack) {
requestSynchronizeStackViewsWithModel();
public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) {
// Compute the transforms of the items in the current stack
final int curScroll = getStackScroll();
final ArrayList<TaskViewTransform> curTaskTransforms =
getStackTransforms(curStack, curScroll, null);
// Restore the stashed scroll
updateMinMaxScroll(false);
setStackScrollRaw(mStashedScroll);
boundScrollRaw();
// Compute the transforms of the items in the new stack
final ArrayList<TaskViewTransform> taskTransforms =
getStackTransforms(mStack.getTasks(), getStackScroll(), null);
// 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
final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
final ArrayList<Task> tasks = mStack.getTasks();
ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
TaskView tv = (TaskView) getChildAt(i);
Task task = tv.getTask();
int taskIndex = tasks.indexOf(task);
TaskViewTransform transform;
// 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);
childrenToRemove.add(tv);
} else {
transform = taskTransforms.get(taskIndex);
}
childViewAnims.add(tv.getAnimatorToTaskTransform(transform));
}
AnimatorSet childViewAnimSet = new AnimatorSet();
childViewAnimSet.setDuration(
Constants.Values.TaskStackView.Animation.UnfilteredCurrentViewsDuration);
childViewAnimSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Return all the removed children to the view pool
for (TaskView tv : childrenToRemove) {
mViewPool.returnViewToPool(tv);
}
// Increment the hw layers ref count
addHwLayersRefCount("unfilteredNewViews");
// 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 offset = 0;
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
TaskViewTransform toTransform = taskTransforms.get(i);
if (toTransform.visible) {
TaskView tv = getChildViewForTask(task);
if (tv == null) {
// For views that are not already visible, animate them in
tv = mViewPool.pickUpViewFromPool(task, task);
// Animate in this new view
TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
newViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
offset++;
}
}
}
// Run the animation
newViewAnimSet.setDuration(
Constants.Values.TaskStackView.Animation.UnfilteredNewViewsDuration);
newViewAnimSet.playTogether(newViewAnims);
newViewAnimSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Decrement the hw layers ref count
decHwLayersRefCount("unfilteredNewViews");
}
});
newViewAnimSet.start();
invalidate();
}
});
childViewAnimSet.playTogether(childViewAnims);
childViewAnimSet.start();
}
/**** ViewPoolConsumer Implementation ****/
@@ -845,7 +1075,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
Console.log(Constants.DebugFlags.UI.TouchEvents,
"[TaskStackViewTouchHandler|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1045,9 +1275,17 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
ActivityManager.REMOVE_TASK_KILL_PROCESS);
}
// If there are no remaining tasks, then just close the activity
// If there are no remaining tasks, then either unfilter the current stack, or just close
// the activity if there are no filtered stacks
if (mSv.mStack.getTaskCount() == 0) {
activity.finish();
boolean shouldFinishActivity = true;
if (mSv.mStack.hasFilteredTasks()) {
mSv.mStack.unfilterTasks();
shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
}
if (shouldFinishActivity) {
activity.finish();
}
}
// Disable HW layers

View File

@@ -16,6 +16,9 @@
package com.android.systemui.recents.views;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
@@ -72,6 +75,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
// Bind the views
mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
mBarView.mActivityIcon.setOnClickListener(this);
if (mTaskDataLoaded) {
onTaskDataLoaded(false);
}
@@ -90,12 +94,16 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
}
@Override
protected void onDraw(Canvas canvas) {
protected void dispatchDraw(Canvas canvas) {
int restoreCount = 0;
if (Constants.Values.TaskView.UseRoundedCorners) {
restoreCount = canvas.save();
canvas.clipPath(mRoundedRectClipPath);
}
super.onDraw(canvas);
super.dispatchDraw(canvas);
if (Constants.Values.TaskView.UseRoundedCorners) {
canvas.restoreToCount(restoreCount);
}
}
/** Set callback */
@@ -109,27 +117,43 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
}
/** Synchronizes this view's properties with the task's transform */
void updateViewPropertiesFromTask(TaskViewTransform animateFromTransform,
TaskViewTransform transform, int duration) {
void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
TaskViewTransform toTransform, int duration) {
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
setScaleX(animateFromTransform.scale);
setScaleY(animateFromTransform.scale);
setAlpha(animateFromTransform.alpha);
}
animate().translationY(transform.translationY)
.scaleX(transform.scale)
.scaleY(transform.scale)
animate().translationY(toTransform.translationY)
.scaleX(toTransform.scale)
.scaleY(toTransform.scale)
.alpha(toTransform.alpha)
.setDuration(duration)
.setInterpolator(new AccelerateDecelerateInterpolator())
.withLayer()
.start();
} else {
setTranslationY(transform.translationY);
setScaleX(transform.scale);
setScaleY(transform.scale);
setTranslationY(toTransform.translationY);
setScaleX(toTransform.scale);
setScaleY(toTransform.scale);
setAlpha(toTransform.alpha);
}
}
/** Returns an animator to animate this task to the specified transform */
Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
AnimatorSet anims = new AnimatorSet();
anims.playTogether(
ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
);
return anims;
}
/** Resets this view's properties */
void resetViewProperties() {
setTranslationX(0f);
@@ -139,6 +163,17 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
setAlpha(1f);
}
void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
// Fade the view out and slide it away
toTransform.alpha = 0f;
toTransform.translationY += 200;
}
void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
// Fade the view in
fromTransform.alpha = 0f;
}
/** Animates this task view as it enters recents */
public void animateOnEnterRecents() {
RecentsConfiguration config = RecentsConfiguration.getInstance();

View File

@@ -23,13 +23,27 @@ import android.graphics.Rect;
public class TaskViewTransform {
public int translationY = 0;
public float scale = 1f;
public boolean visible = true;
public float alpha = 1f;
public boolean visible = false;
public Rect rect = new Rect();
float t;
public TaskViewTransform() {
// Do nothing
}
public TaskViewTransform(TaskViewTransform o) {
translationY = o.translationY;
scale = o.scale;
alpha = o.alpha;
visible = o.visible;
rect.set(o.rect);
t = o.t;
}
@Override
public String toString() {
return "TaskViewTransform y: " + translationY + " scale: " + scale +
return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
" visible: " + visible + " rect: " + rect;
}
}