diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 76e8181407409..be7d3229cb784 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.List; 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 @@ public class AlternateRecentsComponent { 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 @@ public class AlternateRecentsComponent { Context mContext; LayoutInflater mInflater; SystemServicesProxy mSystemServicesProxy; + Handler mHandler; boolean mBootCompleted; + boolean mStartAnimationTriggered; + boolean mCanReuseTaskStackViews = true; // Task launching RecentsConfiguration mConfig; @@ -103,6 +108,7 @@ public class AlternateRecentsComponent { mInflater = LayoutInflater.from(context); mContext = context; mSystemServicesProxy = new SystemServicesProxy(context); + mHandler = new Handler(); mTaskStackBounds = new Rect(); } @@ -128,7 +134,7 @@ public class AlternateRecentsComponent { } // 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 class AlternateRecentsComponent { } 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 @@ public class AlternateRecentsComponent { 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 class AlternateRecentsComponent { } 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 @@ public class AlternateRecentsComponent { * 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 @@ public class AlternateRecentsComponent { 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 @@ public class AlternateRecentsComponent { // 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 @@ public class AlternateRecentsComponent { } 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 @@ public class AlternateRecentsComponent { 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 d2c55f71ca467..f8d981fc2d97d 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.Context; 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } - /** 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } - @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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView /** 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 bfea3f754f7d9..e0c76b1dea026 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 class RecentsConfiguration { 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 @@ public class RecentsConfiguration { 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 4456066827ba0..735f79f4021d6 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 class DozeTrigger { 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 b4f62d5ef4905..390507f12a562 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 @@ public class RecentsTaskLoader { private static final String TAG = "RecentsTaskLoader"; static RecentsTaskLoader sInstance; + public static final int ALL_TASKS = -1; SystemServicesProxy mSystemServicesProxy; DrawableLruCache mApplicationIconCache; @@ -326,10 +327,9 @@ public class RecentsTaskLoader { /** Gets the list of recent tasks, ordered from back to front. */ private static List getRecentTasks(SystemServicesProxy ssp, - boolean isTopTaskHome) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); + int numTasksToLoad, boolean isTopTaskHome) { List tasks = - ssp.getRecentTasks(config.maxNumTasksToLoad, UserHandle.CURRENT.getIdentifier(), + ssp.getRecentTasks(numTasksToLoad, UserHandle.CURRENT.getIdentifier(), isTopTaskHome); Collections.reverse(tasks); return tasks; @@ -416,7 +416,8 @@ public class RecentsTaskLoader { ArrayList taskKeys = new ArrayList(); ArrayList tasksToLoad = new ArrayList(); 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 @@ public class RecentsTaskLoader { } /** Preloads the set of recent tasks (not including thumbnails). */ - public void preload(Context context) { + public void preload(Context context, int numTasksToPreload) { ArrayList tasksToLoad = new ArrayList(); 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 @@ public class RecentsTaskLoader { /** 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 taskKeysOut, List tasksToLoadOut) { RecentsConfiguration config = RecentsConfiguration.getInstance(); - List tasks = getRecentTasks(ssp, isTopTaskHome); + List tasks = getRecentTasks(ssp, + (loadTaskCount == ALL_TASKS ? config.maxNumTasksToLoad : loadTaskCount), + isTopTaskHome); HashMap activityInfoCache = new HashMap(); ArrayList tasksToAdd = new ArrayList(); 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 ff0330dd4f3a6..81ee839b67b27 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -95,42 +95,57 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV /** Set/get the bsp root node */ public void setTaskStacks(ArrayList stacks) { - // Remove all TaskStackViews (but leave the search bar) + int numStacks = stacks.size(); + + // Make a list of the stack view children only + ArrayList stackViews = new ArrayList(); 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 */ @@ -529,6 +544,19 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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 dee26e6e45caa..9df0db611d08a 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 com.android.systemui.recents.model.TaskStack; 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } }; - // 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(context, this); mInflater = LayoutInflater.from(context); mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig); @@ -143,11 +130,62 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void computeScroll() { + if (mStack == null) return; + mStackScroller.computeScroll(); // Synchronize the views synchronizeStackViewsWithModel(); @@ -758,9 +808,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + /** 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // 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 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // 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 7b4e10a74b3d5..790130ac6b354 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 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, 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 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Resets this view's properties */ void resetViewProperties() { setDim(0); + setLayerType(View.LAYER_TYPE_NONE, null); TaskViewTransform.reset(this); } @@ -448,6 +457,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, 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 ba868f5bc90d0..5de84bde822fb 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 @@ public class TaskViewHeader extends FrameLayout { } } + /** 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 af0094ef7e116..12b91affce7de 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 @@ public class ViewPool { mViewCreator.prepareViewToLeavePool(v, prepareData, isNewView); return v; } + + /** Returns an iterator to the list of the views in the pool. */ + Iterator poolViewIterator() { + if (mPool != null) { + return mPool.iterator(); + } + return null; + } }