Ensure that loading and unloading of tasks happen symmetrically with lifecycle events. (Bug 18574950)

Since we were unloading tasks when the activity was stopped, but only reloading
tasks on the next onCreate()/onNewIntent(), there were cases where the system 
would create the activity but then immediately stop and start it (ie. when the
screen is turned off while the activity has resumeWhilePausing=True set in its 
manifest).  This CL ensures that we reload the tasks with the same state used
the last time the Recents activity was started.

The CL also cleans up some visibility state that was confusing and is no longer
necessary, fixes a small issue with the dismiss button flashing when toggling
Recents quickly, and fixes some cases where the initial stack scroll is set
incorrectly.
This commit is contained in:
Winson Chung
2014-12-04 11:43:02 -08:00
parent b255e49fe4
commit 860e2d86d8
7 changed files with 83 additions and 116 deletions

View File

@@ -61,15 +61,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
/** A proxy implementation for the recents component */
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";
final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail";
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 EXTRA_NUM_VISIBLE_TASKS = "recents.numVisibleTasks";
final public static String EXTRA_NUM_VISIBLE_THUMBNAILS = "recents.numVisibleThumbnails";
final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
@@ -550,7 +543,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
mDummyStackView);
if (opts != null) {
startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL, stackVr);
startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
} else {
// Fall through below to the non-thumbnail transition
useThumbnailTransition = false;
@@ -583,12 +577,13 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
}
ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
startAlternateRecentsActivity(topTask, opts,
fromSearchHome ? EXTRA_FROM_SEARCH_HOME : EXTRA_FROM_HOME, stackVr);
startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
false /* fromThumbnail */, stackVr);
} else {
// Otherwise we do the normal fade from an unknown source
ActivityOptions opts = getUnknownTransitionActivityOptions();
startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME, stackVr);
startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
}
}
mLastToggleTime = SystemClock.elapsedRealtime();
@@ -596,21 +591,24 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
/** Starts the recents activity */
void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
ActivityOptions opts, String extraFlag,
ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
// Update the configuration based on the launch options
mConfig.launchedFromHome = fromSearchHome || fromHome;
mConfig.launchedFromSearchHome = fromSearchHome;
mConfig.launchedFromAppWithThumbnail = fromThumbnail;
mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
mConfig.launchedWithAltTab = mTriggeredFromAltTab;
mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
mConfig.launchedHasConfigurationChanged = false;
Intent intent = new Intent(sToggleRecentsAction);
intent.setClassName(sRecentsPackage, sRecentsActivity);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
if (extraFlag != null) {
intent.putExtra(extraFlag, true);
}
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);
intent.putExtra(EXTRA_NUM_VISIBLE_TASKS, vr.numVisibleTasks);
intent.putExtra(EXTRA_NUM_VISIBLE_THUMBNAILS, vr.numVisibleThumbnails);
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {

View File

@@ -108,8 +108,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
public void run() {
// Mark Recents as no longer visible
onRecentsActivityVisibilityChanged(false);
// Finish Recents
if (mLaunchIntent != null) {
if (mLaunchOpts != null) {
@@ -133,8 +131,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) {
// Mark Recents as no longer visible
AlternateRecentsComponent.notifyVisibilityChanged(false);
if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
// If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
dismissRecentsToFocusedTaskOrHome(false);
@@ -186,24 +182,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/** Updates the set of recent tasks */
void updateRecentsTasks(Intent launchIntent) {
// Update the configuration based on the launch intent
boolean fromSearchHome = launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_FROM_SEARCH_HOME, false);
int numVisibleTasks = launchIntent.getIntExtra(
AlternateRecentsComponent.EXTRA_NUM_VISIBLE_TASKS, 0);
int numVisibleThumbnails = launchIntent.getIntExtra(
AlternateRecentsComponent.EXTRA_NUM_VISIBLE_THUMBNAILS, 0);
mConfig.launchedFromHome = fromSearchHome || launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_FROM_HOME, false);
mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
mConfig.launchedToTaskId = launchIntent.getIntExtra(
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);
// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
// reconstructing the task stack
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -218,8 +196,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
loadOpts.runningTaskId = mConfig.launchedToTaskId;
loadOpts.numVisibleTasks = numVisibleTasks;
loadOpts.numVisibleTaskThumbnails = numVisibleThumbnails;
loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;
loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
loader.loadTasks(this, plan, loadOpts);
SpaceNode root = plan.getSpaceNode();
@@ -237,9 +215,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
ActivityOptions.makeCustomAnimation(this,
fromSearchHome ? R.anim.recents_to_search_launcher_enter :
mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
R.anim.recents_to_launcher_enter,
fromSearchHome ? R.anim.recents_to_search_launcher_exit :
mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
R.anim.recents_to_launcher_exit));
// Mark the task that is the launch target
@@ -403,12 +381,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
mScrimViews = new SystemBarScrimViews(this, mConfig);
mStatusBar = ((SystemUIApplication) getApplication())
.getComponent(PhoneStatusBar.class);
inflateDebugOverlay();
// Bind the search app widget when we first start up
bindSearchBarAppWidget();
// Update the recent tasks
updateRecentsTasks(getIntent());
// Register the broadcast receiver to handle messages when the screen is turned off
IntentFilter filter = new IntentFilter();
@@ -424,17 +402,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// Update if we are getting a configuration change
if (savedInstanceState != null) {
// Update RecentsConfiguration
mConfig.updateOnConfigurationChange();
// Trigger the enter animation
onEnterAnimationTriggered();
}
mStatusBar = ((SystemUIApplication) getApplication())
.getComponent(PhoneStatusBar.class);
}
/** Inflates the debug overlay if debug mode is enabled. */
@@ -449,14 +416,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
}
/** Handles changes to the activity visibility. */
void onRecentsActivityVisibilityChanged(boolean visible) {
if (!visible) {
AlternateRecentsComponent.notifyVisibilityChanged(visible);
}
mVisible = visible;
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@@ -469,14 +428,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
if (mDebugOverlay != null) {
mDebugOverlay.clear();
}
// Update the recent tasks
updateRecentsTasks(intent);
}
@Override
protected void onStart() {
super.onStart();
mVisible = true;
AlternateRecentsComponent.notifyVisibilityChanged(true);
// Register the broadcast receiver to handle messages from our service
IntentFilter filter = new IntentFilter();
@@ -487,19 +445,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// Register any broadcast receivers for the task loader
RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
}
@Override
protected void onResume() {
super.onResume();
// Mark Recents as visible
onRecentsActivityVisibilityChanged(true);
// Update the recent tasks
updateRecentsTasks(getIntent());
}
@Override
protected void onStop() {
super.onStop();
mVisible = false;
AlternateRecentsComponent.notifyVisibilityChanged(false);
// Notify the views that we are no longer visible
mRecentsView.onRecentsHidden();
@@ -641,8 +596,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
public void onTaskViewClicked() {
// Mark recents as no longer visible
onRecentsActivityVisibilityChanged(false);
}
@Override

View File

@@ -124,8 +124,12 @@ public class RecentsConfiguration {
public boolean launchedWithNoRecentTasks;
public boolean launchedFromAppWithThumbnail;
public boolean launchedFromHome;
public boolean launchedFromSearchHome;
public boolean launchedReuseTaskStackViews;
public boolean launchedHasConfigurationChanged;
public int launchedToTaskId;
public int launchedNumVisibleTasks;
public int launchedNumVisibleThumbnails;
/** Misc **/
public boolean useHardwareLayers;
@@ -308,12 +312,10 @@ public class RecentsConfiguration {
/** Called when the configuration has changed, and we want to reset any configuration specific
* members. */
public void updateOnConfigurationChange() {
launchedWithAltTab = false;
launchedWithNoRecentTasks = false;
launchedFromAppWithThumbnail = false;
launchedFromHome = false;
// Reset this flag on configuration change to ensure that we recreate new task views
launchedReuseTaskStackViews = false;
launchedToTaskId = -1;
// Set this flag to indicate that the configuration has changed since Recents last launched
launchedHasConfigurationChanged = true;
}
/** Returns whether the search bar app widget exists. */

View File

@@ -715,14 +715,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mStartEnterAnimationContext = null;
}
// When Alt-Tabbing, we scroll to and focus the previous task
// When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
// enter animation).
if (mConfig.launchedWithAltTab) {
if (mConfig.launchedFromHome) {
focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true);
if (mConfig.launchedFromAppWithThumbnail) {
focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
mConfig.launchedHasConfigurationChanged);
} else {
focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true);
focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
mConfig.launchedHasConfigurationChanged);
}
}
// Start dozing
mUIDozeTrigger.startDozing();
}
/** Requests this task stacks to start it's enter-recents animation */
@@ -767,16 +773,27 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
@Override
public void run() {
mStartEnterAnimationCompleted = true;
// Start dozing
mUIDozeTrigger.startDozing();
// Focus the first view if accessibility is enabled
// Poke the dozer to restart the trigger after the animation completes
mUIDozeTrigger.poke();
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
int childCount = getChildCount();
if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
TaskView tv = ((TaskView) getChildAt(childCount - 1));
tv.requestAccessibilityFocus();
mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
if (childCount > 0) {
// Focus the first view if accessibility is enabled
if (ssp.isTouchExplorationEnabled()) {
TaskView tv = ((TaskView) getChildAt(childCount - 1));
tv.requestAccessibilityFocus();
mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
}
}
// Start the focus animation when alt-tabbing
if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) {
View tv = getChildAt(mFocusedTaskIndex);
if (tv != null) {
((TaskView) tv).setFocusedTask(true);
}
}
}
});

View File

@@ -135,7 +135,6 @@ public class TaskStackViewLayoutAlgorithm {
// Update the task offsets
float pAtBackMostCardTop = 0.5f;
float pAtFrontMostCardTop = pAtBackMostCardTop;
float pAtSecondFrontMostCardTop = pAtBackMostCardTop;
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
@@ -145,25 +144,19 @@ public class TaskStackViewLayoutAlgorithm {
// Increment the peek height
float pPeek = task.group.isFrontMostTask(task) ?
pBetweenAffiliateOffset : pWithinAffiliateOffset;
pAtSecondFrontMostCardTop = pAtFrontMostCardTop;
pAtFrontMostCardTop += pPeek;
}
}
mMaxScrollP = pAtFrontMostCardTop - ((1f - pTaskHeightOffset - pNavBarOffset));
mMinScrollP = tasks.size() == 1 ? Math.max(mMaxScrollP, 0f) : 0f;
if (launchedWithAltTab) {
if (launchedFromHome) {
// Center the top most task, since that will be focused first
mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f;
} else {
// Center the second top most task, since that will be focused first
mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f;
}
if (launchedWithAltTab && launchedFromHome) {
// Center the top most task, since that will be focused first
mInitialScrollP = mMaxScrollP;
} else {
mInitialScrollP = pAtFrontMostCardTop - 0.825f;
}
mInitialScrollP = Math.max(0, mInitialScrollP);
mInitialScrollP = Math.min(mMaxScrollP, Math.max(0, mInitialScrollP));
}
/**

View File

@@ -235,7 +235,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
boolean occludesLaunchTarget, int offscreenY) {
int initialDim = getDim();
if (mConfig.launchedFromAppWithThumbnail) {
if (mConfig.launchedHasConfigurationChanged) {
// Just load the views as-is
} else if (mConfig.launchedFromAppWithThumbnail) {
if (isTaskViewLaunchTargetTask) {
// Set the dim to 0 so we can animate it in
initialDim = 0;

View File

@@ -237,15 +237,17 @@ public class TaskViewHeader extends FrameLayout {
/** Animates this task bar if the user does not interact with the stack after a certain time. */
void startNoUserInteractionAnimation() {
mDismissButton.setVisibility(View.VISIBLE);
mDismissButton.setAlpha(0f);
mDismissButton.animate()
.alpha(1f)
.setStartDelay(0)
.setInterpolator(mConfig.fastOutLinearInInterpolator)
.setDuration(mConfig.taskViewEnterFromAppDuration)
.withLayer()
.start();
if (mDismissButton.getVisibility() != View.VISIBLE) {
mDismissButton.setVisibility(View.VISIBLE);
mDismissButton.setAlpha(0f);
mDismissButton.animate()
.alpha(1f)
.setStartDelay(0)
.setInterpolator(mConfig.fastOutLinearInInterpolator)
.setDuration(mConfig.taskViewEnterFromAppDuration)
.withLayer()
.start();
}
}
/** Mark this task view that the user does has not interacted with the stack after a certain time. */