Split ActivityStack.ensureActivitiesVisibleLocked.
Change-Id: I027b52f76c868bf7b0a04efcca965e812bf3d35c
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9896ec5..e28d198 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1418,19 +1418,9 @@
if (top == null) {
return;
}
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "ensureActivitiesVisible behind " + top
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
-
- if (mTranslucentActivityWaiting != top) {
- mUndrawnActivitiesBelowTopTranslucent.clear();
- if (mTranslucentActivityWaiting != null) {
- // Call the callback with a timeout indication.
- notifyActivityDrawnLocked(null);
- mTranslucentActivityWaiting = null;
- }
- mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
- }
+ checkTranslucentActivityWaiting(top);
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
@@ -1458,7 +1448,6 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Make visible? " + r + " finishing=" + r.finishing
+ " state=" + r.state);
-
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting) {
@@ -1466,143 +1455,28 @@
}
if (r.app == null || r.app.thread == null) {
- // We need to make sure the app is running if it's the top, or it is
- // just made visible from invisible.
- // If the app is already visible, it must have died while it was visible.
- // In this case, we'll show the dead window but will not restart the app.
- // Otherwise we could end up thrashing.
- if (r == top || !r.visible) {
- // This activity needs to be visible, but isn't even running...
- // get it started and resume if no other stack in this stack is resumed.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Start and freeze screen for " + r);
- if (r != starting) {
- r.startFreezingScreenLocked(r.app, configChanges);
- }
- if (!r.visible || r.mLaunchTaskBehind) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Starting and making visible: " + r);
- setVisible(r, true);
- }
- if (r != starting) {
- mStackSupervisor.startSpecificActivityLocked(
- r, noStackActivityResumed, false);
- if (activityNdx >= activities.size()) {
- // Record may be removed if its process needs to restart.
- activityNdx = activities.size() - 1;
- } else {
- noStackActivityResumed = false;
- }
+ if (makeVisibleAndRestartIfNeeded(starting, configChanges, top,
+ noStackActivityResumed, r)) {
+ if (activityNdx >= activities.size()) {
+ // Record may be removed if its process needs to restart.
+ activityNdx = activities.size() - 1;
+ } else {
+ noStackActivityResumed = false;
}
}
} else if (r.visible) {
- // If this activity is already visible, then there is nothing
- // else to do here.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Skipping: already visible at " + r);
- r.stopFreezingScreenLocked(false);
- try {
- if (r.returningOptions != null) {
- r.app.thread.scheduleOnNewActivityOptions(r.appToken,
- r.returningOptions);
- }
- } catch(RemoteException e) {
- }
- if (r.state == ActivityState.RESUMED) {
+ if (alreadyVisible(r)) {
noStackActivityResumed = false;
}
} else {
- // This activity is not currently visible, but is running.
- // Tell it to become visible.
- r.visible = true;
- if (r.state != ActivityState.RESUMED && r != starting) {
- // If this activity is paused, tell it
- // to now show its window.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Making visible and scheduling visibility: " + r);
- try {
- if (mTranslucentActivityWaiting != null) {
- r.updateOptionsLocked(r.returningOptions);
- mUndrawnActivitiesBelowTopTranslucent.add(r);
- }
- setVisible(r, true);
- r.sleeping = false;
- r.app.pendingUiClean = true;
- r.app.thread.scheduleWindowVisibility(r.appToken, true);
- r.stopFreezingScreenLocked(false);
- } catch (Exception e) {
- // Just skip on any failure; we'll make it
- // visible when it next restarts.
- Slog.w(TAG, "Exception thrown making visibile: "
- + r.intent.getComponent(), e);
- }
- }
+ becomeVisible(starting, r);
}
-
// Aggregate current change flags.
configChanges |= r.configChangeFlags;
-
- if (r.fullscreen) {
- // At this point, nothing else needs to be shown in this task.
- behindFullscreenActivity = true;
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
- behindFullscreenActivity = true;
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- }
+ behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
+ behindFullscreenActivity, task, r);
} else {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Make invisible? " + r + " finishing=" + r.finishing
- + " state=" + r.state + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // Now for any activities that aren't visible to the user, make
- // sure they no longer are keeping the screen frozen.
- if (r.visible) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
- try {
- setVisible(r, false);
- switch (r.state) {
- case STOPPING:
- case STOPPED:
- if (r.app != null && r.app.thread != null) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Scheduling invisibility: " + r);
- r.app.thread.scheduleWindowVisibility(r.appToken, false);
- }
- break;
-
- case INITIALIZING:
- case RESUMED:
- case PAUSING:
- case PAUSED:
- // This case created for transitioning activities from
- // translucent to opaque {@link Activity#convertToOpaque}.
- if (getVisibleBehindActivity() == r) {
- releaseBackgroundResources(r);
- } else {
- if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- mStackSupervisor.mStoppingActivities.add(r);
- }
- mStackSupervisor.scheduleIdleLocked();
- }
- break;
-
- default:
- break;
- }
- } catch (Exception e) {
- // Just skip on any failure; we'll make it
- // visible when it next restarts.
- Slog.w(TAG, "Exception thrown making hidden: "
- + r.intent.getComponent(), e);
- }
- } else {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
- }
+ becomeInvisible(stackInvisible, behindFullscreenActivity, r);
}
}
if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
@@ -1620,6 +1494,147 @@
}
}
+ private void checkTranslucentActivityWaiting(ActivityRecord top) {
+ if (mTranslucentActivityWaiting != top) {
+ mUndrawnActivitiesBelowTopTranslucent.clear();
+ if (mTranslucentActivityWaiting != null) {
+ // Call the callback with a timeout indication.
+ notifyActivityDrawnLocked(null);
+ mTranslucentActivityWaiting = null;
+ }
+ mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
+ }
+ }
+
+ private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
+ ActivityRecord top, boolean noStackActivityResumed, ActivityRecord r) {
+ // We need to make sure the app is running if it's the top, or it is just made visible from
+ // invisible. If the app is already visible, it must have died while it was visible. In this
+ // case, we'll show the dead window but will not restart the app. Otherwise we could end up
+ // thrashing.
+ if (r == top || !r.visible) {
+ // This activity needs to be visible, but isn't even running...
+ // get it started and resume if no other stack in this stack is resumed.
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
+ if (r != starting) {
+ r.startFreezingScreenLocked(r.app, configChanges);
+ }
+ if (!r.visible || r.mLaunchTaskBehind) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
+ setVisible(r, true);
+ }
+ if (r != starting) {
+ mStackSupervisor.startSpecificActivityLocked(r, noStackActivityResumed, false);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void becomeInvisible(boolean stackInvisible, boolean behindFullscreenActivity,
+ ActivityRecord r) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r + " finishing="
+ + r.finishing + " state=" + r.state + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ if (!r.visible) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
+ return;
+ }
+ // Now for any activities that aren't visible to the user, make sure they no longer are
+ // keeping the screen frozen.
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
+ try {
+ setVisible(r, false);
+ switch (r.state) {
+ case STOPPING:
+ case STOPPED:
+ if (r.app != null && r.app.thread != null) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Scheduling invisibility: " + r);
+ r.app.thread.scheduleWindowVisibility(r.appToken, false);
+ }
+ break;
+
+ case INITIALIZING:
+ case RESUMED:
+ case PAUSING:
+ case PAUSED:
+ // This case created for transitioning activities from
+ // translucent to opaque {@link Activity#convertToOpaque}.
+ if (getVisibleBehindActivity() == r) {
+ releaseBackgroundResources(r);
+ } else {
+ if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+ mStackSupervisor.mStoppingActivities.add(r);
+ }
+ mStackSupervisor.scheduleIdleLocked();
+ }
+ break;
+
+ default:
+ break;
+ }
+ } catch (Exception e) {
+ // Just skip on any failure; we'll make it visible when it next restarts.
+ Slog.w(TAG, "Exception thrown making hidden: " + r.intent.getComponent(), e);
+ }
+ }
+
+ private boolean updateBehindFullscreen(boolean stackInvisible, boolean behindFullscreenActivity,
+ TaskRecord task, ActivityRecord r) {
+ if (r.fullscreen) {
+ // At this point, nothing else needs to be shown in this task.
+ behindFullscreenActivity = true;
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
+ behindFullscreenActivity = true;
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ }
+ return behindFullscreenActivity;
+ }
+
+ private void becomeVisible(ActivityRecord starting, ActivityRecord r) {
+ // This activity is not currently visible, but is running. Tell it to become visible.
+ r.visible = true;
+ if (r.state != ActivityState.RESUMED && r != starting) {
+ // If this activity is paused, tell it to now show its window.
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Making visible and scheduling visibility: " + r);
+ try {
+ if (mTranslucentActivityWaiting != null) {
+ r.updateOptionsLocked(r.returningOptions);
+ mUndrawnActivitiesBelowTopTranslucent.add(r);
+ }
+ setVisible(r, true);
+ r.sleeping = false;
+ r.app.pendingUiClean = true;
+ r.app.thread.scheduleWindowVisibility(r.appToken, true);
+ r.stopFreezingScreenLocked(false);
+ } catch (Exception e) {
+ // Just skip on any failure; we'll make it
+ // visible when it next restarts.
+ Slog.w(TAG, "Exception thrown making visibile: " + r.intent.getComponent(), e);
+ }
+ }
+ }
+
+ private boolean alreadyVisible(ActivityRecord r) {
+ // If this activity is already visible, then there is nothing else to do here.
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping: already visible at " + r);
+ r.stopFreezingScreenLocked(false);
+ try {
+ if (r.returningOptions != null) {
+ r.app.thread.scheduleOnNewActivityOptions(r.appToken, r.returningOptions);
+ }
+ } catch(RemoteException e) {
+ }
+ return r.state == ActivityState.RESUMED;
+ }
+
void convertActivityToTranslucent(ActivityRecord r) {
mTranslucentActivityWaiting = r;
mUndrawnActivitiesBelowTopTranslucent.clear();