Don't reload the layout every time we enter Recents. (Bug 18160176)
Ensure that we don't reinflate new TaskViews whenever we enter Recents by
keeping the existing TaskStackViews active and returning the existing
TaskViews back into the view pool when Recents is no longer visible.
This CL also ensures that we are preloading the appropriate task metadata
when the user first touches the nav bar, and also reverts the change to use
onEnterAnimationComplete() in favor of the explicitly animation-started
broadcast (to ensure we always get the signal) which fixes a regression
with launching Recents in landscape.
Change-Id: I169fea3cf07a6da3f90b32b005819773c6049ada
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 76e8181..be7d322 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -54,7 +54,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
/** A proxy implementation for the recents component */
-public class AlternateRecentsComponent {
+public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome";
@@ -62,7 +62,9 @@
final public static String EXTRA_FROM_TASK_ID = "recents.activeTaskId";
final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey";
+ final public static String EXTRA_REUSE_TASK_STACK_VIEWS = "recents.reuseTaskStackViews";
+ final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
@@ -77,7 +79,10 @@
Context mContext;
LayoutInflater mInflater;
SystemServicesProxy mSystemServicesProxy;
+ Handler mHandler;
boolean mBootCompleted;
+ boolean mStartAnimationTriggered;
+ boolean mCanReuseTaskStackViews = true;
// Task launching
RecentsConfiguration mConfig;
@@ -103,6 +108,7 @@
mInflater = LayoutInflater.from(context);
mContext = context;
mSystemServicesProxy = new SystemServicesProxy(context);
+ mHandler = new Handler();
mTaskStackBounds = new Rect();
}
@@ -128,7 +134,7 @@
}
// When we start, preload the metadata associated with the previous tasks
- RecentsTaskLoader.getInstance().preload(mContext);
+ RecentsTaskLoader.getInstance().preload(mContext, RecentsTaskLoader.ALL_TASKS);
}
public void onBootCompleted() {
@@ -176,7 +182,9 @@
}
public void onPreloadRecents() {
- // Do nothing
+ // When we start, preload the metadata associated with the previous tasks
+ RecentsTaskLoader.getInstance().preload(mContext,
+ Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
}
public void onCancelPreloadingRecents() {
@@ -186,7 +194,7 @@
void showRelativeAffiliatedTask(boolean showNextTask) {
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(),
- -1, -1, false, true, null, null);
+ -1, -1, RecentsTaskLoader.ALL_TASKS, false, true, null, null);
// Return early if there are no tasks
if (stack.getTaskCount() == 0) return;
@@ -251,6 +259,8 @@
}
public void onConfigurationChanged(Configuration newConfig) {
+ // Don't reuse task stack views if the configuration changes
+ mCanReuseTaskStackViews = false;
// Reload the header bar layout
reloadHeaderBarLayout();
}
@@ -364,23 +374,28 @@
* Creates the activity options for a unknown state->recents transition.
*/
ActivityOptions getUnknownTransitionActivityOptions() {
+ mStartAnimationTriggered = false;
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_unknown_enter,
- R.anim.recents_from_unknown_exit);
+ R.anim.recents_from_unknown_exit,
+ mHandler, this);
}
/**
* Creates the activity options for a home->recents transition.
*/
ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
+ mStartAnimationTriggered = false;
if (fromSearchHome) {
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_search_launcher_enter,
- R.anim.recents_from_search_launcher_exit);
+ R.anim.recents_from_search_launcher_exit,
+ mHandler, this);
}
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter,
- R.anim.recents_from_launcher_exit);
+ R.anim.recents_from_launcher_exit,
+ mHandler, this);
}
/**
@@ -408,9 +423,10 @@
c.setBitmap(null);
}
+ mStartAnimationTriggered = false;
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView,
thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
- toTaskRect.height(), null);
+ toTaskRect.height(), this);
}
// If both the screenshot and thumbnail fails, then just fall back to the default transition
@@ -423,7 +439,7 @@
// Get the stack of tasks that we are animating into
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(),
- runningTaskId, -1, false, isTopTaskHome, null, null);
+ runningTaskId, -1, RecentsTaskLoader.ALL_TASKS, false, isTopTaskHome, null, null);
if (stack.getTaskCount() == 0) {
return null;
}
@@ -529,11 +545,13 @@
}
intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
intent.putExtra(EXTRA_FROM_TASK_ID, (topTask != null) ? topTask.id : -1);
+ intent.putExtra(EXTRA_REUSE_TASK_STACK_VIEWS, mCanReuseTaskStackViews);
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
+ mCanReuseTaskStackViews = true;
}
/** Sets the RecentsComponent callbacks. */
@@ -547,4 +565,42 @@
sRecentsComponentCallbacks.onVisibilityChanged(visible);
}
}
+
+ /**** OnAnimationStartedListener Implementation ****/
+
+ @Override
+ public void onAnimationStarted() {
+ // Notify recents to start the enter animation
+ if (!mStartAnimationTriggered) {
+ // There can be a race condition between the start animation callback and
+ // the start of the new activity (where we register the receiver that listens
+ // to this broadcast, so we add our own receiver and if that gets called, then
+ // we know the activity has not yet started and we can retry sending the broadcast.
+ BroadcastReceiver fallbackReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getResultCode() == Activity.RESULT_OK) {
+ mStartAnimationTriggered = true;
+ return;
+ }
+
+ // Schedule for the broadcast to be sent again after some time
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ onAnimationStarted();
+ }
+ }, 25);
+ }
+ };
+
+ // Send the broadcast to notify Recents that the animation has started
+ Intent intent = new Intent(ACTION_START_ENTER_ANIMATION);
+ intent.setPackage(mContext.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+ fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d2c55f7..f8d981f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -27,6 +27,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -142,6 +143,12 @@
} else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// If we are toggling Recents, then first unfilter any filtered stacks first
dismissRecentsToFocusedTaskOrHome(true);
+ } else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) {
+ // Trigger the enter animation
+ onEnterAnimationTriggered();
+ // Notify the fallback receiver that we have successfully got the broadcast
+ // See AlternateRecentsComponent.onAnimationStarted()
+ setResultCode(Activity.RESULT_OK);
}
}
};
@@ -157,7 +164,8 @@
// When the screen turns off, dismiss Recents to Home
dismissRecentsToHome(false);
// Start preloading some tasks in the background
- RecentsTaskLoader.getInstance().preload(RecentsActivity.this);
+ RecentsTaskLoader.getInstance().preload(RecentsActivity.this,
+ Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
} else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
// When the search activity changes, update the Search widget
refreshSearchWidget();
@@ -188,6 +196,8 @@
AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1);
mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
+ mConfig.launchedReuseTaskStackViews = launchIntent.getBooleanExtra(
+ AlternateRecentsComponent.EXTRA_REUSE_TASK_STACK_VIEWS, false);
// Load all the tasks
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -397,8 +407,12 @@
// Update if we are getting a configuration change
if (savedInstanceState != null) {
+ // Update RecentsConfiguration
+ mConfig = RecentsConfiguration.reinitialize(this,
+ RecentsTaskLoader.getInstance().getSystemServicesProxy());
mConfig.updateOnConfigurationChange();
- onConfigurationChange();
+ // Trigger the enter animation
+ onEnterAnimationTriggered();
}
// Start listening for widget package changes if there is one bound, post it since we don't
@@ -428,19 +442,6 @@
}
}
- /** Called when the configuration changes. */
- void onConfigurationChange() {
- // Update RecentsConfiguration
- mConfig = RecentsConfiguration.reinitialize(this,
- RecentsTaskLoader.getInstance().getSystemServicesProxy());
-
- // Try and start the enter animation (or restart it on configuration changed)
- ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
- mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
- // Animate the SystemUI scrim views
- mScrimViews.startEnterRecentsAnimation();
- }
-
/** Handles changes to the activity visibility. */
void onRecentsActivityVisibilityChanged(boolean visible) {
if (!visible) {
@@ -474,6 +475,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY);
filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY);
+ filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION);
registerReceiver(mServiceBroadcastReceiver, filter);
// Register any broadcast receivers for the task loader
@@ -492,8 +494,8 @@
protected void onStop() {
super.onStop();
- // Remove all the views
- mRecentsView.removeAllTaskStacks();
+ // Notify the views that we are no longer visible
+ mRecentsView.onRecentsHidden();
// Unregister the RecentsService receiver
unregisterReceiver(mServiceBroadcastReceiver);
@@ -515,8 +517,7 @@
}
}
- @Override
- public void onEnterAnimationComplete() {
+ public void onEnterAnimationTriggered() {
// Try and start the enter animation (or restart it on configuration changed)
ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
@@ -584,7 +585,6 @@
/** Called when debug mode is triggered */
public void onDebugModeTriggered() {
-
if (mConfig.developerOptionsEnabled) {
SharedPreferences settings = getSharedPreferences(getPackageName(), 0);
if (settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false)) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index bfea3f7..e0c76b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -115,8 +115,8 @@
public boolean launchedWithAltTab;
public boolean launchedWithNoRecentTasks;
public boolean launchedFromAppWithThumbnail;
- public boolean launchedFromAppWithScreenshot;
public boolean launchedFromHome;
+ public boolean launchedReuseTaskStackViews;
public int launchedToTaskId;
/** Misc **/
@@ -308,6 +308,7 @@
launchedWithNoRecentTasks = false;
launchedFromAppWithThumbnail = false;
launchedFromHome = false;
+ launchedReuseTaskStackViews = false;
launchedToTaskId = -1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 4456066..735f79f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -82,4 +82,9 @@
public boolean hasTriggered() {
return mHasTriggered;
}
+
+ /** Resets the doze trigger state. */
+ public void resetTrigger() {
+ mHasTriggered = false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index b4f62d5..390507f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -260,6 +260,7 @@
private static final String TAG = "RecentsTaskLoader";
static RecentsTaskLoader sInstance;
+ public static final int ALL_TASKS = -1;
SystemServicesProxy mSystemServicesProxy;
DrawableLruCache mApplicationIconCache;
@@ -326,10 +327,9 @@
/** Gets the list of recent tasks, ordered from back to front. */
private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp,
- boolean isTopTaskHome) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
+ int numTasksToLoad, boolean isTopTaskHome) {
List<ActivityManager.RecentTaskInfo> tasks =
- ssp.getRecentTasks(config.maxNumTasksToLoad, UserHandle.CURRENT.getIdentifier(),
+ ssp.getRecentTasks(numTasksToLoad, UserHandle.CURRENT.getIdentifier(),
isTopTaskHome);
Collections.reverse(tasks);
return tasks;
@@ -416,7 +416,8 @@
ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
ArrayList<Task> tasksToLoad = new ArrayList<Task>();
TaskStack stack = getTaskStack(mSystemServicesProxy, context.getResources(),
- -1, preloadCount, true, isTopTaskHome, taskKeys, tasksToLoad);
+ -1, preloadCount, RecentsTaskLoader.ALL_TASKS, true, isTopTaskHome, taskKeys,
+ tasksToLoad);
SpaceNode root = new SpaceNode();
root.setStack(stack);
@@ -428,10 +429,10 @@
}
/** Preloads the set of recent tasks (not including thumbnails). */
- public void preload(Context context) {
+ public void preload(Context context, int numTasksToPreload) {
ArrayList<Task> tasksToLoad = new ArrayList<Task>();
getTaskStack(mSystemServicesProxy, context.getResources(),
- -1, -1, true, true, null, tasksToLoad);
+ -1, -1, numTasksToPreload, true, true, null, tasksToLoad);
// Start the task loader and add all the tasks we need to load
mLoadQueue.addTasks(tasksToLoad);
@@ -440,11 +441,13 @@
/** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
public synchronized TaskStack getTaskStack(SystemServicesProxy ssp, Resources res,
- int preloadTaskId, int preloadTaskCount,
+ int preloadTaskId, int preloadTaskCount, int loadTaskCount,
boolean loadTaskThumbnails, boolean isTopTaskHome,
List<Task.TaskKey> taskKeysOut, List<Task> tasksToLoadOut) {
RecentsConfiguration config = RecentsConfiguration.getInstance();
- List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp, isTopTaskHome);
+ List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp,
+ (loadTaskCount == ALL_TASKS ? config.maxNumTasksToLoad : loadTaskCount),
+ isTopTaskHome);
HashMap<Task.ComponentNameKey, ActivityInfoHandle> activityInfoCache =
new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
ArrayList<Task> tasksToAdd = new ArrayList<Task>();
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 6b0d306..80dcb28 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -96,42 +96,57 @@
/** Set/get the bsp root node */
public void setTaskStacks(ArrayList<TaskStack> stacks) {
- // Remove all TaskStackViews (but leave the search bar)
+ int numStacks = stacks.size();
+
+ // Make a list of the stack view children only
+ ArrayList<TaskStackView> stackViews = new ArrayList<TaskStackView>();
int childCount = getChildCount();
- for (int i = childCount - 1; i >= 0; i--) {
- View v = getChildAt(i);
- if (v != mSearchBar) {
- removeViewAt(i);
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child != mSearchBar) {
+ stackViews.add((TaskStackView) child);
}
}
- // Create and add all the stacks for this partition of space.
+ // Remove all/extra stack views
+ int numTaskStacksToKeep = 0; // Keep no tasks if we are recreating the layout
+ if (mConfig.launchedReuseTaskStackViews) {
+ numTaskStacksToKeep = Math.min(childCount, numStacks);
+ }
+ for (int i = stackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
+ removeView(stackViews.get(i));
+ stackViews.remove(i);
+ }
+
+ // Update the stack views that we are keeping
+ for (int i = 0; i < numTaskStacksToKeep; i++) {
+ stackViews.get(i).setStack(stacks.get(i));
+ }
+
+ // Add remaining/recreate stack views
mStacks = stacks;
- int numStacks = mStacks.size();
- for (int i = 0; i < numStacks; i++) {
- TaskStack stack = mStacks.get(i);
+ for (int i = stackViews.size(); i < numStacks; i++) {
+ TaskStack stack = stacks.get(i);
TaskStackView stackView = new TaskStackView(getContext(), stack);
stackView.setCallbacks(this);
- // Enable debug mode drawing
- if (mConfig.debugModeEnabled) {
- stackView.setDebugOverlay(mDebugOverlay);
- }
addView(stackView);
}
+ // Enable debug mode drawing on all the stacks if necessary
+ if (mConfig.debugModeEnabled) {
+ for (int i = childCount - 1; i >= 0; i--) {
+ View v = getChildAt(i);
+ if (v != mSearchBar) {
+ TaskStackView stackView = (TaskStackView) v;
+ stackView.setDebugOverlay(mDebugOverlay);
+ }
+ }
+ }
+
// Reset the launched state
mAlreadyLaunchingTask = false;
- }
-
- /** Removes all the task stack views from this recents view. */
- public void removeAllTaskStacks() {
- int childCount = getChildCount();
- for (int i = childCount - 1; i >= 0; i--) {
- View child = getChildAt(i);
- if (child != mSearchBar) {
- removeViewAt(i);
- }
- }
+ // Trigger a new layout
+ requestLayout();
}
/** Launches the focused task from the first stack if possible */
@@ -531,6 +546,19 @@
mCb.onAllTaskViewsDismissed();
}
+ /** Final callback after Recents is finally hidden. */
+ public void onRecentsHidden() {
+ // Notify each task stack view
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child != mSearchBar) {
+ TaskStackView stackView = (TaskStackView) child;
+ stackView.onRecentsHidden();
+ }
+ }
+ }
+
@Override
public void onTaskStackFilterTriggered() {
// Hide the search bar
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 dee26e6..9df0db6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -40,6 +40,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
/* The visual representation of a task stack view */
@@ -99,25 +100,11 @@
}
};
- // A convenience runnable to return all views to the pool
- Runnable mReturnAllViewsToPoolRunnable = new Runnable() {
- @Override
- public void run() {
- int childCount = getChildCount();
- for (int i = childCount - 1; i >= 0; i--) {
- TaskView tv = (TaskView) getChildAt(i);
- mViewPool.returnViewToPool(tv);
- // Also hide the view since we don't need it anymore
- tv.setVisibility(View.INVISIBLE);
- }
- }
- };
-
public TaskStackView(Context context, TaskStack stack) {
super(context);
+ // Set the stack first
+ setStack(stack);
mConfig = RecentsConfiguration.getInstance();
- mStack = stack;
- mStack.setCallbacks(this);
mViewPool = new ViewPool<TaskView, Task>(context, this);
mInflater = LayoutInflater.from(context);
mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig);
@@ -143,11 +130,62 @@
mCb = cb;
}
+ /** Sets the task stack */
+ void setStack(TaskStack stack) {
+ // Unset the old stack
+ if (mStack != null) {
+ mStack.setCallbacks(null);
+
+ // Return all existing views to the pool
+ reset();
+ // Layout again with the new stack
+ requestLayout();
+ }
+
+ // Set the new stack
+ mStack = stack;
+ if (mStack != null) {
+ mStack.setCallbacks(this);
+ }
+ }
+
/** Sets the debug overlay */
public void setDebugOverlay(DebugOverlayView overlay) {
mDebugOverlay = overlay;
}
+ /** Resets this TaskStackView for reuse. */
+ void reset() {
+ // Return all the views to the pool
+ int childCount = getChildCount();
+ for (int i = childCount - 1; i >= 0; i--) {
+ TaskView tv = (TaskView) getChildAt(i);
+ mViewPool.returnViewToPool(tv);
+ }
+
+ // Mark each task view for relayout
+ if (mViewPool != null) {
+ Iterator<TaskView> iter = mViewPool.poolViewIterator();
+ if (iter != null) {
+ while (iter.hasNext()) {
+ TaskView tv = iter.next();
+ tv.reset();
+ }
+ }
+ }
+
+ // Reset the stack state
+ resetFocusedTask();
+ mStackViewsDirty = true;
+ mStackViewsClipDirty = true;
+ mAwaitingFirstLayout = true;
+ mPrevAccessibilityFocusedIndex = -1;
+ if (mUIDozeTrigger != null) {
+ mUIDozeTrigger.stopDozing();
+ mUIDozeTrigger.resetTrigger();
+ }
+ }
+
/** Requests that the views be synchronized with the model */
void requestSynchronizeStackViewsWithModel() {
requestSynchronizeStackViewsWithModel(0);
@@ -510,6 +548,16 @@
tv.dismissTask();
}
+ /** Resets the focused task. */
+ void resetFocusedTask() {
+ if (mFocusedTaskIndex > -1) {
+ Task t = mStack.getTasks().get(mFocusedTaskIndex);
+ TaskView tv = getChildViewForTask(t);
+ tv.unsetFocusedTask();
+ }
+ mFocusedTaskIndex = -1;
+ }
+
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
@@ -543,6 +591,8 @@
@Override
public void computeScroll() {
+ if (mStack == null) return;
+
mStackScroller.computeScroll();
// Synchronize the views
synchronizeStackViewsWithModel();
@@ -758,9 +808,6 @@
TaskView tv = (TaskView) getChildAt(i);
tv.startExitToHomeAnimation(ctx);
}
-
- // Add a runnable to the post animation ref counter to clear all the views
- ctx.postAnimationTrigger.addLastDecrementRunnable(mReturnAllViewsToPoolRunnable);
}
/** Animates a task view in this stack as it launches. */
@@ -780,6 +827,12 @@
}
}
+ /** Final callback after Recents is finally hidden. */
+ void onRecentsHidden() {
+ reset();
+ setStack(null);
+ }
+
public boolean isTransformedTouchPointInView(float x, float y, View child) {
return isTransformedTouchPointInView(x, y, child, null);
}
@@ -944,20 +997,23 @@
// Reset the view properties
tv.resetViewProperties();
+
+ // Reset the clip state of the task view
+ tv.setClipViewInStack(false);
}
@Override
public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) {
+ // It is possible for a view to be returned to the view pool before it is laid out,
+ // which means that we will need to relayout the view when it is first used next.
+ boolean requiresRelayout = tv.getWidth() <= 0 && !isNewView;
+
// Rebind the task and request that this task's data be filled into the TaskView
tv.onTaskBound(task);
// Load the task data
RecentsTaskLoader.getInstance().loadTaskData(task);
- // Sanity check, the task view should always be clipping against the stack at this point,
- // but just in case, re-enable it here
- tv.setClipViewInStack(true);
-
// If the doze trigger has already fired, then update the state for this task view
if (mUIDozeTrigger.hasTriggered()) {
tv.setNoUserInteractionState();
@@ -985,13 +1041,17 @@
// Add/attach the view to the hierarchy
if (isNewView) {
addView(tv, insertIndex);
-
- // Set the callbacks and listeners for this new view
- tv.setTouchEnabled(true);
- tv.setCallbacks(this);
} else {
attachViewToParent(tv, insertIndex, tv.getLayoutParams());
+ if (requiresRelayout) {
+ tv.requestLayout();
+ }
}
+
+ // Set the new state for this view, including the callbacks and view clipping
+ tv.setCallbacks(this);
+ tv.setTouchEnabled(true);
+ tv.setClipViewInStack(true);
}
@Override
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 7b4e10a..790130a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -112,6 +112,14 @@
mCb = cb;
}
+ /** Resets this TaskView for reuse. */
+ void reset() {
+ resetViewProperties();
+ resetNoUserInteractionState();
+ setClipViewInStack(false);
+ setCallbacks(null);
+ }
+
/** Gets the task */
Task getTask() {
return mTask;
@@ -191,6 +199,7 @@
/** Resets this view's properties */
void resetViewProperties() {
setDim(0);
+ setLayerType(View.LAYER_TYPE_NONE, null);
TaskViewTransform.reset(this);
}
@@ -448,6 +457,11 @@
mHeaderView.setNoUserInteractionState();
}
+ /** Resets the state tracking that the user has not interacted with the stack after a certain time. */
+ void resetNoUserInteractionState() {
+ mHeaderView.resetNoUserInteractionState();
+ }
+
/** Dismisses this task. */
void dismissTask() {
// Animate out the view and call the callback
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index ba868f5..5de84bd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -263,6 +263,11 @@
}
}
+ /** Resets the state tracking that the user has not interacted with the stack after a certain time. */
+ void resetNoUserInteractionState() {
+ mDismissButton.setVisibility(View.INVISIBLE);
+ }
+
@Override
protected int[] onCreateDrawableState(int extraSpace) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
index af0094e..12b91af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java
@@ -75,4 +75,12 @@
mViewCreator.prepareViewToLeavePool(v, prepareData, isNewView);
return v;
}
+
+ /** Returns an iterator to the list of the views in the pool. */
+ Iterator<V> poolViewIterator() {
+ if (mPool != null) {
+ return mPool.iterator();
+ }
+ return null;
+ }
}