am 6ac3367d: Merge "Enabling filtering by base intent package."
* commit '6ac3367d5df999736470f29a2bbb623864f06d1a': Enabling filtering by base intent package.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user