summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/layout/recents_task_view.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Constants.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Utilities.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/Task.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java338
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java18
12 files changed, 390 insertions, 95 deletions
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f6e875c..f5ce222 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -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"
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index b5950e9..2b08141 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -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;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b65b864..dd75921 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -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();
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 515cec1..22363bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -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);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index b497b69..90c83d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -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());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index 33e4246..9048cba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -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) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index cda4ab2..677334d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -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() + "]";
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index f2f89ae..a0e5b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -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);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index cc85439..e89bde5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -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);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e7f517f..aeb571d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -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
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index c86b0e1..e04a1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -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();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 66c52a0..0748bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -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;
}
}