am e0325fe9: Merge "Don\'t reload the layout every time we enter Recents. (Bug 18160176)" into lmp-mr1-dev

* commit 'e0325fe956c2a33b79added92f0e53be2246506a':
  Don't reload the layout every time we enter Recents. (Bug 18160176)
This commit is contained in:
Winson Chung
2014-11-06 19:26:11 +00:00
committed by Android Git Automerger
10 changed files with 269 additions and 89 deletions

View File

@@ -54,7 +54,7 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
/** A proxy implementation for the recents component */ /** 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_HOME = "recents.triggeredOverHome";
final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome"; 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_FROM_TASK_ID = "recents.activeTaskId";
final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab"; 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_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_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity"; final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
@@ -77,7 +79,10 @@ public class AlternateRecentsComponent {
Context mContext; Context mContext;
LayoutInflater mInflater; LayoutInflater mInflater;
SystemServicesProxy mSystemServicesProxy; SystemServicesProxy mSystemServicesProxy;
Handler mHandler;
boolean mBootCompleted; boolean mBootCompleted;
boolean mStartAnimationTriggered;
boolean mCanReuseTaskStackViews = true;
// Task launching // Task launching
RecentsConfiguration mConfig; RecentsConfiguration mConfig;
@@ -103,6 +108,7 @@ public class AlternateRecentsComponent {
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
mContext = context; mContext = context;
mSystemServicesProxy = new SystemServicesProxy(context); mSystemServicesProxy = new SystemServicesProxy(context);
mHandler = new Handler();
mTaskStackBounds = new Rect(); mTaskStackBounds = new Rect();
} }
@@ -128,7 +134,7 @@ public class AlternateRecentsComponent {
} }
// When we start, preload the metadata associated with the previous tasks // 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() { public void onBootCompleted() {
@@ -176,7 +182,9 @@ public class AlternateRecentsComponent {
} }
public void onPreloadRecents() { 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() { public void onCancelPreloadingRecents() {
@@ -186,7 +194,7 @@ public class AlternateRecentsComponent {
void showRelativeAffiliatedTask(boolean showNextTask) { void showRelativeAffiliatedTask(boolean showNextTask) {
RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(), 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 // Return early if there are no tasks
if (stack.getTaskCount() == 0) return; if (stack.getTaskCount() == 0) return;
@@ -251,6 +259,8 @@ public class AlternateRecentsComponent {
} }
public void onConfigurationChanged(Configuration newConfig) { public void onConfigurationChanged(Configuration newConfig) {
// Don't reuse task stack views if the configuration changes
mCanReuseTaskStackViews = false;
// Reload the header bar layout // Reload the header bar layout
reloadHeaderBarLayout(); reloadHeaderBarLayout();
} }
@@ -364,23 +374,28 @@ public class AlternateRecentsComponent {
* Creates the activity options for a unknown state->recents transition. * Creates the activity options for a unknown state->recents transition.
*/ */
ActivityOptions getUnknownTransitionActivityOptions() { ActivityOptions getUnknownTransitionActivityOptions() {
mStartAnimationTriggered = false;
return ActivityOptions.makeCustomAnimation(mContext, return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_unknown_enter, 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. * Creates the activity options for a home->recents transition.
*/ */
ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) { ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
mStartAnimationTriggered = false;
if (fromSearchHome) { if (fromSearchHome) {
return ActivityOptions.makeCustomAnimation(mContext, return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_search_launcher_enter, 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, return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter, 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); c.setBitmap(null);
} }
mStartAnimationTriggered = false;
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView, return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView,
thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), 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 // 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 // Get the stack of tasks that we are animating into
RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(), 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) { if (stack.getTaskCount() == 0) {
return null; return null;
} }
@@ -529,11 +545,13 @@ public class AlternateRecentsComponent {
} }
intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab); intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
intent.putExtra(EXTRA_FROM_TASK_ID, (topTask != null) ? topTask.id : -1); intent.putExtra(EXTRA_FROM_TASK_ID, (topTask != null) ? topTask.id : -1);
intent.putExtra(EXTRA_REUSE_TASK_STACK_VIEWS, mCanReuseTaskStackViews);
if (opts != null) { if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT); mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else { } else {
mContext.startActivityAsUser(intent, UserHandle.CURRENT); mContext.startActivityAsUser(intent, UserHandle.CURRENT);
} }
mCanReuseTaskStackViews = true;
} }
/** Sets the RecentsComponent callbacks. */ /** Sets the RecentsComponent callbacks. */
@@ -547,4 +565,42 @@ public class AlternateRecentsComponent {
sRecentsComponentCallbacks.onVisibilityChanged(visible); 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);
}
}
} }

View File

@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; 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)) { } else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// If we are toggling Recents, then first unfilter any filtered stacks first // If we are toggling Recents, then first unfilter any filtered stacks first
dismissRecentsToFocusedTaskOrHome(true); 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 // When the screen turns off, dismiss Recents to Home
dismissRecentsToHome(false); dismissRecentsToHome(false);
// Start preloading some tasks in the background // 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)) { } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
// When the search activity changes, update the Search widget // When the search activity changes, update the Search widget
refreshSearchWidget(); refreshSearchWidget();
@@ -188,6 +196,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1); AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1);
mConfig.launchedWithAltTab = launchIntent.getBooleanExtra( mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false); AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
mConfig.launchedReuseTaskStackViews = launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_REUSE_TASK_STACK_VIEWS, false);
// Load all the tasks // Load all the tasks
RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -397,8 +407,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// Update if we are getting a configuration change // Update if we are getting a configuration change
if (savedInstanceState != null) { if (savedInstanceState != null) {
// Update RecentsConfiguration
mConfig = RecentsConfiguration.reinitialize(this,
RecentsTaskLoader.getInstance().getSystemServicesProxy());
mConfig.updateOnConfigurationChange(); 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 // 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. */ /** Handles changes to the activity visibility. */
void onRecentsActivityVisibilityChanged(boolean visible) { void onRecentsActivityVisibilityChanged(boolean visible) {
if (!visible) { if (!visible) {
@@ -474,6 +475,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY); filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY);
filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY); filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY);
filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION);
registerReceiver(mServiceBroadcastReceiver, filter); registerReceiver(mServiceBroadcastReceiver, filter);
// Register any broadcast receivers for the task loader // Register any broadcast receivers for the task loader
@@ -492,8 +494,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
protected void onStop() { protected void onStop() {
super.onStop(); super.onStop();
// Remove all the views // Notify the views that we are no longer visible
mRecentsView.removeAllTaskStacks(); mRecentsView.onRecentsHidden();
// Unregister the RecentsService receiver // Unregister the RecentsService receiver
unregisterReceiver(mServiceBroadcastReceiver); unregisterReceiver(mServiceBroadcastReceiver);
@@ -515,8 +517,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
} }
} }
@Override public void onEnterAnimationTriggered() {
public void onEnterAnimationComplete() {
// Try and start the enter animation (or restart it on configuration changed) // Try and start the enter animation (or restart it on configuration changed)
ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t));
@@ -584,7 +585,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/** Called when debug mode is triggered */ /** Called when debug mode is triggered */
public void onDebugModeTriggered() { public void onDebugModeTriggered() {
if (mConfig.developerOptionsEnabled) { if (mConfig.developerOptionsEnabled) {
SharedPreferences settings = getSharedPreferences(getPackageName(), 0); SharedPreferences settings = getSharedPreferences(getPackageName(), 0);
if (settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false)) { if (settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false)) {

View File

@@ -115,8 +115,8 @@ public class RecentsConfiguration {
public boolean launchedWithAltTab; public boolean launchedWithAltTab;
public boolean launchedWithNoRecentTasks; public boolean launchedWithNoRecentTasks;
public boolean launchedFromAppWithThumbnail; public boolean launchedFromAppWithThumbnail;
public boolean launchedFromAppWithScreenshot;
public boolean launchedFromHome; public boolean launchedFromHome;
public boolean launchedReuseTaskStackViews;
public int launchedToTaskId; public int launchedToTaskId;
/** Misc **/ /** Misc **/
@@ -308,6 +308,7 @@ public class RecentsConfiguration {
launchedWithNoRecentTasks = false; launchedWithNoRecentTasks = false;
launchedFromAppWithThumbnail = false; launchedFromAppWithThumbnail = false;
launchedFromHome = false; launchedFromHome = false;
launchedReuseTaskStackViews = false;
launchedToTaskId = -1; launchedToTaskId = -1;
} }

View File

@@ -82,4 +82,9 @@ public class DozeTrigger {
public boolean hasTriggered() { public boolean hasTriggered() {
return mHasTriggered; return mHasTriggered;
} }
/** Resets the doze trigger state. */
public void resetTrigger() {
mHasTriggered = false;
}
} }

View File

@@ -260,6 +260,7 @@ public class RecentsTaskLoader {
private static final String TAG = "RecentsTaskLoader"; private static final String TAG = "RecentsTaskLoader";
static RecentsTaskLoader sInstance; static RecentsTaskLoader sInstance;
public static final int ALL_TASKS = -1;
SystemServicesProxy mSystemServicesProxy; SystemServicesProxy mSystemServicesProxy;
DrawableLruCache mApplicationIconCache; DrawableLruCache mApplicationIconCache;
@@ -326,10 +327,9 @@ public class RecentsTaskLoader {
/** Gets the list of recent tasks, ordered from back to front. */ /** Gets the list of recent tasks, ordered from back to front. */
private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp, private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp,
boolean isTopTaskHome) { int numTasksToLoad, boolean isTopTaskHome) {
RecentsConfiguration config = RecentsConfiguration.getInstance();
List<ActivityManager.RecentTaskInfo> tasks = List<ActivityManager.RecentTaskInfo> tasks =
ssp.getRecentTasks(config.maxNumTasksToLoad, UserHandle.CURRENT.getIdentifier(), ssp.getRecentTasks(numTasksToLoad, UserHandle.CURRENT.getIdentifier(),
isTopTaskHome); isTopTaskHome);
Collections.reverse(tasks); Collections.reverse(tasks);
return tasks; return tasks;
@@ -416,7 +416,8 @@ public class RecentsTaskLoader {
ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>(); ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
ArrayList<Task> tasksToLoad = new ArrayList<Task>(); ArrayList<Task> tasksToLoad = new ArrayList<Task>();
TaskStack stack = getTaskStack(mSystemServicesProxy, context.getResources(), 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(); SpaceNode root = new SpaceNode();
root.setStack(stack); root.setStack(stack);
@@ -428,10 +429,10 @@ public class RecentsTaskLoader {
} }
/** Preloads the set of recent tasks (not including thumbnails). */ /** 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>(); ArrayList<Task> tasksToLoad = new ArrayList<Task>();
getTaskStack(mSystemServicesProxy, context.getResources(), 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 // Start the task loader and add all the tasks we need to load
mLoadQueue.addTasks(tasksToLoad); mLoadQueue.addTasks(tasksToLoad);
@@ -440,11 +441,13 @@ public class RecentsTaskLoader {
/** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */ /** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
public synchronized TaskStack getTaskStack(SystemServicesProxy ssp, Resources res, public synchronized TaskStack getTaskStack(SystemServicesProxy ssp, Resources res,
int preloadTaskId, int preloadTaskCount, int preloadTaskId, int preloadTaskCount, int loadTaskCount,
boolean loadTaskThumbnails, boolean isTopTaskHome, boolean loadTaskThumbnails, boolean isTopTaskHome,
List<Task.TaskKey> taskKeysOut, List<Task> tasksToLoadOut) { List<Task.TaskKey> taskKeysOut, List<Task> tasksToLoadOut) {
RecentsConfiguration config = RecentsConfiguration.getInstance(); 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 = HashMap<Task.ComponentNameKey, ActivityInfoHandle> activityInfoCache =
new HashMap<Task.ComponentNameKey, ActivityInfoHandle>(); new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
ArrayList<Task> tasksToAdd = new ArrayList<Task>(); ArrayList<Task> tasksToAdd = new ArrayList<Task>();

View File

@@ -95,42 +95,57 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/** Set/get the bsp root node */ /** Set/get the bsp root node */
public void setTaskStacks(ArrayList<TaskStack> stacks) { 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(); int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) { for (int i = 0; i < childCount; i++) {
View v = getChildAt(i); View child = getChildAt(i);
if (v != mSearchBar) { if (child != mSearchBar) {
removeViewAt(i); 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; mStacks = stacks;
int numStacks = mStacks.size(); for (int i = stackViews.size(); i < numStacks; i++) {
for (int i = 0; i < numStacks; i++) { TaskStack stack = stacks.get(i);
TaskStack stack = mStacks.get(i);
TaskStackView stackView = new TaskStackView(getContext(), stack); TaskStackView stackView = new TaskStackView(getContext(), stack);
stackView.setCallbacks(this); stackView.setCallbacks(this);
// Enable debug mode drawing
if (mConfig.debugModeEnabled) {
stackView.setDebugOverlay(mDebugOverlay);
}
addView(stackView); 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 // Reset the launched state
mAlreadyLaunchingTask = false; mAlreadyLaunchingTask = false;
} // Trigger a new layout
requestLayout();
/** 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);
}
}
} }
/** Launches the focused task from the first stack if possible */ /** Launches the focused task from the first stack if possible */
@@ -529,6 +544,19 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
mCb.onAllTaskViewsDismissed(); 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 @Override
public void onTaskStackFilterTriggered() { public void onTaskStackFilterTriggered() {
// Hide the search bar // Hide the search bar

View File

@@ -40,6 +40,7 @@ import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
/* The visual representation of a task stack view */ /* 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) { public TaskStackView(Context context, TaskStack stack) {
super(context); super(context);
// Set the stack first
setStack(stack);
mConfig = RecentsConfiguration.getInstance(); mConfig = RecentsConfiguration.getInstance();
mStack = stack;
mStack.setCallbacks(this);
mViewPool = new ViewPool<TaskView, Task>(context, this); mViewPool = new ViewPool<TaskView, Task>(context, this);
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig); mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig);
@@ -143,11 +130,62 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mCb = cb; 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 */ /** Sets the debug overlay */
public void setDebugOverlay(DebugOverlayView overlay) { public void setDebugOverlay(DebugOverlayView overlay) {
mDebugOverlay = 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 */ /** Requests that the views be synchronized with the model */
void requestSynchronizeStackViewsWithModel() { void requestSynchronizeStackViewsWithModel() {
requestSynchronizeStackViewsWithModel(0); requestSynchronizeStackViewsWithModel(0);
@@ -510,6 +548,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
tv.dismissTask(); 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 @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) { public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event); super.onInitializeAccessibilityEvent(event);
@@ -543,6 +591,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
@Override @Override
public void computeScroll() { public void computeScroll() {
if (mStack == null) return;
mStackScroller.computeScroll(); mStackScroller.computeScroll();
// Synchronize the views // Synchronize the views
synchronizeStackViewsWithModel(); synchronizeStackViewsWithModel();
@@ -758,9 +808,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskView tv = (TaskView) getChildAt(i); TaskView tv = (TaskView) getChildAt(i);
tv.startExitToHomeAnimation(ctx); 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. */ /** 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) { public boolean isTransformedTouchPointInView(float x, float y, View child) {
return isTransformedTouchPointInView(x, y, child, null); return isTransformedTouchPointInView(x, y, child, null);
} }
@@ -944,20 +997,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Reset the view properties // Reset the view properties
tv.resetViewProperties(); tv.resetViewProperties();
// Reset the clip state of the task view
tv.setClipViewInStack(false);
} }
@Override @Override
public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) { 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 // Rebind the task and request that this task's data be filled into the TaskView
tv.onTaskBound(task); tv.onTaskBound(task);
// Load the task data // Load the task data
RecentsTaskLoader.getInstance().loadTaskData(task); 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 the doze trigger has already fired, then update the state for this task view
if (mUIDozeTrigger.hasTriggered()) { if (mUIDozeTrigger.hasTriggered()) {
tv.setNoUserInteractionState(); tv.setNoUserInteractionState();
@@ -985,13 +1041,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Add/attach the view to the hierarchy // Add/attach the view to the hierarchy
if (isNewView) { if (isNewView) {
addView(tv, insertIndex); addView(tv, insertIndex);
// Set the callbacks and listeners for this new view
tv.setTouchEnabled(true);
tv.setCallbacks(this);
} else { } else {
attachViewToParent(tv, insertIndex, tv.getLayoutParams()); 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 @Override

View File

@@ -112,6 +112,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
mCb = cb; mCb = cb;
} }
/** Resets this TaskView for reuse. */
void reset() {
resetViewProperties();
resetNoUserInteractionState();
setClipViewInStack(false);
setCallbacks(null);
}
/** Gets the task */ /** Gets the task */
Task getTask() { Task getTask() {
return mTask; return mTask;
@@ -191,6 +199,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
/** Resets this view's properties */ /** Resets this view's properties */
void resetViewProperties() { void resetViewProperties() {
setDim(0); setDim(0);
setLayerType(View.LAYER_TYPE_NONE, null);
TaskViewTransform.reset(this); TaskViewTransform.reset(this);
} }
@@ -448,6 +457,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
mHeaderView.setNoUserInteractionState(); 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. */ /** Dismisses this task. */
void dismissTask() { void dismissTask() {
// Animate out the view and call the callback // Animate out the view and call the callback

View File

@@ -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 @Override
protected int[] onCreateDrawableState(int extraSpace) { protected int[] onCreateDrawableState(int extraSpace) {

View File

@@ -75,4 +75,12 @@ public class ViewPool<V, T> {
mViewCreator.prepareViewToLeavePool(v, prepareData, isNewView); mViewCreator.prepareViewToLeavePool(v, prepareData, isNewView);
return v; 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;
}
} }