ActivityStack cleanup
- Moved some methods that mostly operate with internals of
ActivityRecord and/or logically should belong their to
ActivityRecord class.
- Reduced visibility of some methods and fields.
- Other minor cleanups.
Test: Manual and existing tests still pass.
Change-Id: I87ed6987c88512dda3cd69fa43a1f093d47d0bff
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70c4fb2..b346529 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4793,7 +4793,8 @@
final long origId = Binder.clearCallingIdentity();
try {
r.forceNewConfig = true;
- r.getStack().ensureActivityConfigurationLocked(r, 0, false);
+ r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+ false /* preserveWindow */);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -6901,10 +6902,7 @@
public final void activityResumed(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- stack.activityResumedLocked(token);
- }
+ ActivityRecord.activityResumedLocked(token);
}
Binder.restoreCallingIdentity(origId);
}
@@ -6936,7 +6934,7 @@
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.getStack().activityStoppedLocked(r, icicle, persistentState, description);
+ r.activityStoppedLocked(icicle, persistentState, description);
}
}
@@ -19117,7 +19115,8 @@
}
if (starting != null) {
- kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false);
+ kept = starting.ensureActivityConfigurationLocked(changes,
+ false /* preserveWindow */);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9317605..e8b8869 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,24 +17,41 @@
package com.android.server.am;
import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import android.annotation.NonNull;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.PendingIntent;
@@ -49,6 +66,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.IBinder;
import android.os.Message;
import android.os.PersistableBundle;
@@ -80,6 +98,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import org.xmlpull.v1.XmlPullParser;
@@ -91,12 +110,16 @@
*/
final class ActivityRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
+ private static final String TAG_SCREENSHOTS = TAG + POSTFIX_SCREENSHOTS;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_THUMBNAILS = TAG + POSTFIX_THUMBNAILS;
+ private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final boolean SHOW_ACTIVITY_START_TIME = true;
- final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
+ private static final String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
private static final String ATTR_ID = "id";
private static final String TAG_INTENT = "intent";
@@ -149,11 +172,11 @@
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
long pauseTime; // last time we started pausing the activity
long launchTickTime; // base time for launch tick messages
- Configuration mLastReportedConfiguration; // configuration activity was last running in
+ private Configuration mLastReportedConfiguration; // configuration activity was last running in
// Overridden configuration by the activity task
// WARNING: Reference points to {@link TaskRecord#getMergedOverrideConfig}, so its internal
// state should never be altered directly.
- Configuration mLastReportedOverrideConfiguration;
+ private Configuration mLastReportedOverrideConfiguration;
CompatibilityInfo compat;// last used compatibility mode
ActivityRecord resultTo; // who started this entry, so will get our reply
final String resultWho; // additional identifier for use by resultTo.
@@ -230,6 +253,12 @@
// on the window.
int mRotationAnimationHint = -1;
+ /**
+ * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
+ */
+ private final Configuration mTmpGlobalConfig = new Configuration();
+ private final Configuration mTmpTaskConfig = new Configuration();
+
private static String startingWindowStateToString(int state) {
switch (state) {
case STARTING_WINDOW_NOT_SHOWN:
@@ -402,15 +431,15 @@
}
}
- public boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
+ private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp);
}
- public boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) {
+ private boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mVerticalSizeConfigurations, firstDp, secondDp);
}
- public boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
+ private boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mSmallestSizeConfigurations, firstDp, secondDp);
}
@@ -443,14 +472,14 @@
return false;
}
- public void setSizeConfigurations(int[] horizontalSizeConfiguration,
+ void setSizeConfigurations(int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
mHorizontalSizeConfigurations = horizontalSizeConfiguration;
mVerticalSizeConfigurations = verticalSizeConfigurations;
mSmallestSizeConfigurations = smallestSizeConfigurations;
}
- void scheduleConfigurationChanged(Configuration config, boolean reportToActivity) {
+ private void scheduleConfigurationChanged(Configuration config, boolean reportToActivity) {
if (app == null || app.thread == null) {
return;
}
@@ -529,7 +558,6 @@
if (r != null) {
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
r.nowVisible = false;
- return;
}
}
}
@@ -545,7 +573,7 @@
return false;
}
anrActivity = r.getWaitingHistoryRecordLocked();
- anrApp = r != null ? r.app : null;
+ anrApp = r.app;
}
return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
}
@@ -562,7 +590,7 @@
}
}
- private static final ActivityRecord tokenToActivityRecordLocked(Token token) {
+ private static ActivityRecord tokenToActivityRecordLocked(Token token) {
if (token == null) {
return null;
}
@@ -941,7 +969,7 @@
}
}
- void addNewIntentLocked(ReferrerIntent intent) {
+ private void addNewIntentLocked(ReferrerIntent intent) {
if (newIntents == null) {
newIntents = new ArrayList<>();
}
@@ -1122,12 +1150,251 @@
"Setting thumbnail of " + this + " to " + newThumbnail);
boolean thumbnailUpdated = task.setLastThumbnailLocked(newThumbnail);
if (thumbnailUpdated && isPersistable()) {
- mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
+ service.notifyTaskPersisterLocked(task, false);
}
}
task.lastDescription = description;
}
+ final Bitmap screenshotActivityLocked() {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivityLocked: " + this);
+ if (noDisplay) {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
+ return null;
+ }
+
+ final ActivityStack stack = getStack();
+ if (stack.isHomeStack()) {
+ // This is an optimization -- since we never show Home or Recents within Recents itself,
+ // we can just go ahead and skip taking the screenshot if this is the home stack.
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tHome stack");
+ return null;
+ }
+
+ int w = service.mThumbnailWidth;
+ int h = service.mThumbnailHeight;
+
+ if (w <= 0) {
+ Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
+ return null;
+ }
+
+ if (stack.mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
+ // When the docked stack is minimized its app windows are cropped significantly so any
+ // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
+ // in that case.
+ if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
+ return null;
+ }
+
+ final float scale;
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
+
+ // When this flag is set, we currently take the fullscreen screenshot of the activity but
+ // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
+ // SystemUI while keeping memory usage low.
+ if (TAKE_FULLSCREEN_SCREENSHOTS) {
+ w = h = -1;
+ scale = service.mFullscreenThumbnailScale;
+ }
+
+ return service.mWindowManager.screenshotApplications(appToken, DEFAULT_DISPLAY, w, h,
+ scale);
+ }
+
+ void setVisible(boolean newVisible) {
+ visible = newVisible;
+ if (!visible && mUpdateTaskThumbnailWhenHidden) {
+ updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
+ mUpdateTaskThumbnailWhenHidden = false;
+ }
+ service.mWindowManager.setAppVisibility(appToken, visible);
+ final ArrayList<ActivityContainer> containers = mChildContainers;
+ for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
+ final ActivityContainer container = containers.get(containerNdx);
+ container.setVisible(visible);
+ }
+ mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+ }
+
+ /** Return true if the input activity should be made visible */
+ boolean shouldBeVisible(boolean behindTranslucentActivity, boolean stackVisibleBehind,
+ ActivityRecord visibleBehind, boolean behindFullscreenActivity) {
+ if (!okToShowLocked()) {
+ return false;
+ }
+
+ // mLaunchingBehind: Activities launching behind are at the back of the task stack
+ // but must be drawn initially for the animation as though they were visible.
+ final boolean activityVisibleBehind =
+ (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == this;
+
+ boolean isVisible =
+ !behindFullscreenActivity || mLaunchTaskBehind || activityVisibleBehind;
+
+ if (service.mSupportsLeanbackOnly && isVisible && isRecentsActivity()) {
+ // On devices that support leanback only (Android TV), Recents activity can only be
+ // visible if the home stack is the focused stack or we are in split-screen mode.
+ isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null
+ || mStackSupervisor.isFocusedStack(getStack());
+ }
+
+ return isVisible;
+ }
+
+ void makeVisibleIfNeeded(ActivityRecord starting) {
+ // This activity is not currently visible, but is running. Tell it to become visible.
+ if (state == ActivityState.RESUMED || this == starting) {
+ if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
+ "Not making visible, r=" + this + " state=" + state + " starting=" + starting);
+ return;
+ }
+
+ // If this activity is paused, tell it to now show its window.
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Making visible and scheduling visibility: " + this);
+ final ActivityStack stack = getStack();
+ try {
+ if (stack.mTranslucentActivityWaiting != null) {
+ updateOptionsLocked(returningOptions);
+ stack.mUndrawnActivitiesBelowTopTranslucent.add(this);
+ }
+ setVisible(true);
+ sleeping = false;
+ app.pendingUiClean = true;
+ app.thread.scheduleWindowVisibility(appToken, true /* showWindow */);
+ // The activity may be waiting for stop, but that is no longer appropriate for it.
+ mStackSupervisor.mStoppingActivities.remove(this);
+ mStackSupervisor.mGoingToSleepActivities.remove(this);
+ } catch (Exception e) {
+ // Just skip on any failure; we'll make it visible when it next restarts.
+ Slog.w(TAG, "Exception thrown making visibile: " + intent.getComponent(), e);
+ }
+ handleAlreadyVisible();
+ }
+
+ boolean handleAlreadyVisible() {
+ stopFreezingScreenLocked(false);
+ try {
+ if (returningOptions != null) {
+ app.thread.scheduleOnNewActivityOptions(appToken, returningOptions);
+ }
+ } catch(RemoteException e) {
+ }
+ return state == ActivityState.RESUMED;
+ }
+
+ static void activityResumedLocked(IBinder token) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
+ if (r != null) {
+ r.icicle = null;
+ r.haveState = false;
+ }
+ }
+
+ /**
+ * Once we know that we have asked an application to put an activity in the resumed state
+ * (either by launching it or explicitly telling it), this function updates the rest of our
+ * state to match that fact.
+ */
+ void completeResumeLocked() {
+ final boolean wasVisible = visible;
+ visible = true;
+ if (!wasVisible) {
+ // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
+ mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+ }
+ idle = false;
+ results = null;
+ newIntents = null;
+ stopped = false;
+
+ if (isHomeActivity()) {
+ ProcessRecord app = task.mActivities.get(0).app;
+ if (app != null && app != service.mHomeProcess) {
+ service.mHomeProcess = app;
+ }
+ }
+
+ if (nowVisible) {
+ // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
+ mStackSupervisor.reportActivityVisibleLocked(this);
+ mStackSupervisor.notifyActivityDrawnForKeyguard();
+ }
+
+ // Schedule an idle timeout in case the app doesn't do it for us.
+ mStackSupervisor.scheduleIdleTimeoutLocked(this);
+
+ mStackSupervisor.reportResumedActivityLocked(this);
+
+ resumeKeyDispatchingLocked();
+ final ActivityStack stack = getStack();
+ stack.mNoAnimActivities.clear();
+
+ // Mark the point when the activity is resuming
+ // TODO: To be more accurate, the mark should be before the onCreate,
+ // not after the onResume. But for subsequent starts, onResume is fine.
+ if (app != null) {
+ cpuTimeAtResume = service.mProcessCpuTracker.getCpuTimeForPid(app.pid);
+ } else {
+ cpuTimeAtResume = 0; // Couldn't get the cpu time of process
+ }
+
+ returningOptions = null;
+
+ if (stack.getVisibleBehindActivity() == this) {
+ // When resuming an activity, require it to call requestVisibleBehind() again.
+ stack.setVisibleBehindActivity(null /* ActivityRecord */);
+ }
+ mStackSupervisor.checkReadyForSleepLocked();
+ }
+
+ final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
+ CharSequence description) {
+ final ActivityStack stack = getStack();
+ if (state != ActivityState.STOPPING) {
+ Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
+ stack.mHandler.removeMessages(ActivityStack.STOP_TIMEOUT_MSG, this);
+ return;
+ }
+ if (newPersistentState != null) {
+ persistentState = newPersistentState;
+ service.notifyTaskPersisterLocked(task, false);
+ }
+ if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
+ if (newIcicle != null) {
+ // If icicle is null, this is happening due to a timeout, so we haven't really saved
+ // the state.
+ icicle = newIcicle;
+ haveState = true;
+ launchCount = 0;
+ updateThumbnailLocked(null /* newThumbnail */, description);
+ }
+ if (!stopped) {
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
+ stack.mHandler.removeMessages(ActivityStack.STOP_TIMEOUT_MSG, this);
+ stopped = true;
+ state = ActivityState.STOPPED;
+
+ service.mWindowManager.notifyAppStopped(appToken);
+
+ if (stack.getVisibleBehindActivity() == this) {
+ mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
+ }
+ if (finishing) {
+ clearOptionsLocked();
+ } else {
+ if (deferRelaunchUntilPaused) {
+ stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config");
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ } else {
+ mStackSupervisor.updatePreviousProcessLocked(this);
+ }
+ }
+ }
+ }
+
void startLaunchTickingLocked() {
if (ActivityManagerService.IS_USER_BUILD) {
return;
@@ -1435,6 +1702,255 @@
}
}
+ // TODO: now used only in one place to address race-condition. Remove when that will be fixed.
+ void setLastReportedConfiguration(@NonNull Configuration config) {
+ mLastReportedConfiguration.setTo(config);
+ }
+
+ /** Call when override config was sent to the Window Manager to update internal records. */
+ void onOverrideConfigurationSent() {
+ mLastReportedOverrideConfiguration.setTo(task.getMergedOverrideConfiguration());
+ }
+
+ /**
+ * Make sure the given activity matches the current configuration. Returns false if the activity
+ * had to be destroyed. Returns true if the configuration is the same, or the activity will
+ * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
+ * correct configuration and all other bookkeeping is handled.
+ */
+ boolean ensureActivityConfigurationLocked(int globalChanges, boolean preserveWindow) {
+ final ActivityStack stack = getStack();
+ if (stack.mConfigWillChange) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Skipping config check (will change): " + this);
+ return true;
+ }
+
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Ensuring correct configuration: " + this);
+
+ // Short circuit: if the two configurations are equal (the common case), then there is
+ // nothing to do.
+ final Configuration newGlobalConfig = service.getGlobalConfiguration();
+ final Configuration newTaskMergedOverrideConfig = task.getMergedOverrideConfiguration();
+ if (mLastReportedConfiguration.equals(newGlobalConfig)
+ && mLastReportedOverrideConfiguration.equals(newTaskMergedOverrideConfig)
+ && !forceNewConfig) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration unchanged in " + this);
+ return true;
+ }
+
+ // We don't worry about activities that are finishing.
+ if (finishing) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration doesn't matter in finishing " + this);
+ stopFreezingScreenLocked(false);
+ return true;
+ }
+
+ // Okay we now are going to make this activity have the new config.
+ // But then we need to figure out how it needs to deal with that.
+ mTmpGlobalConfig.setTo(mLastReportedConfiguration);
+ mTmpTaskConfig.setTo(mLastReportedOverrideConfiguration);
+ mLastReportedConfiguration.setTo(newGlobalConfig);
+ mLastReportedOverrideConfiguration.setTo(newTaskMergedOverrideConfig);
+
+ int taskChanges = getTaskConfigurationChanges(this, newTaskMergedOverrideConfig,
+ mTmpTaskConfig);
+ final int changes = mTmpGlobalConfig.diff(newGlobalConfig) | taskChanges;
+ if (changes == 0 && !forceNewConfig) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration no differences in " + this);
+ // There are no significant differences, so we won't relaunch but should still deliver
+ // the new configuration to the client process.
+ scheduleConfigurationChanged(newTaskMergedOverrideConfig, true);
+ return true;
+ }
+
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration changes for " + this + " ; taskChanges="
+ + Configuration.configurationDiffToString(taskChanges) + ", allChanges="
+ + Configuration.configurationDiffToString(changes));
+
+ // If the activity isn't currently running, just leave the new configuration and it will
+ // pick that up next time it starts.
+ if (app == null || app.thread == null) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration doesn't matter not running " + this);
+ stopFreezingScreenLocked(false);
+ forceNewConfig = false;
+ return true;
+ }
+
+ // Figure out how to handle the changes between the configurations.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Checking to restart " + info.name + ": changed=0x"
+ + Integer.toHexString(changes) + ", handles=0x"
+ + Integer.toHexString(info.getRealConfigChanged())
+ + ", newGlobalConfig=" + newGlobalConfig
+ + ", newTaskMergedOverrideConfig=" + newTaskMergedOverrideConfig);
+
+ if ((changes&(~info.getRealConfigChanged())) != 0 || forceNewConfig) {
+ // Aha, the activity isn't handling the change, so DIE DIE DIE.
+ configChangeFlags |= changes;
+ startFreezingScreenLocked(app, globalChanges);
+ forceNewConfig = false;
+ preserveWindow &= isResizeOnlyChange(changes);
+ if (app == null || app.thread == null) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is destroying non-running " + this);
+ stack.destroyActivityLocked(this, true, "config");
+ } else if (state == ActivityState.PAUSING) {
+ // A little annoying: we are waiting for this activity to finish pausing. Let's not
+ // do anything now, but just flag that it needs to be restarted when done pausing.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is skipping already pausing " + this);
+ deferRelaunchUntilPaused = true;
+ preserveWindowOnDeferredRelaunch = preserveWindow;
+ return true;
+ } else if (state == ActivityState.RESUMED) {
+ // Try to optimize this case: the configuration is changing and we need to restart
+ // the top, resumed activity. Instead of doing the normal handshaking, just say
+ // "restart!".
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is relaunching resumed " + this);
+
+ if (DEBUG_STATES && !visible) {
+ Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + this
+ + " called by " + Debug.getCallers(4));
+ }
+
+ relaunchActivityLocked(true /* andResume */, preserveWindow);
+ } else {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is relaunching non-resumed " + this);
+ relaunchActivityLocked(false /* andResume */, preserveWindow);
+ }
+
+ // All done... tell the caller we weren't able to keep this activity around.
+ return false;
+ }
+
+ // Default case: the activity can handle this new configuration, so hand it over.
+ // NOTE: We only forward the task override configuration as the system level configuration
+ // changes is always sent to all processes when they happen so it can just use whatever
+ // system level configuration it last got.
+ scheduleConfigurationChanged(newTaskMergedOverrideConfig, true);
+ stopFreezingScreenLocked(false);
+
+ return true;
+ }
+
+ private static int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
+ Configuration oldTaskOverride) {
+ // If we went from full-screen to non-full-screen, make sure to use the correct
+ // configuration task diff, so the diff stays as small as possible.
+ if (Configuration.EMPTY.equals(oldTaskOverride)
+ && !Configuration.EMPTY.equals(taskConfig)) {
+ oldTaskOverride = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
+ }
+
+ // Conversely, do the same when going the other direction.
+ if (Configuration.EMPTY.equals(taskConfig)
+ && !Configuration.EMPTY.equals(oldTaskOverride)) {
+ taskConfig = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
+ }
+
+ // Determine what has changed. May be nothing, if this is a config that has come back from
+ // the app after going idle. In that case we just want to leave the official config object
+ // now in the activity and do nothing else.
+ int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */);
+ // We don't want to use size changes if they don't cross boundaries that are important to
+ // the app.
+ if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
+ final boolean crosses = record.crossesHorizontalSizeThreshold(
+ oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp)
+ || record.crossesVerticalSizeThreshold(
+ oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp);
+ if (!crosses) {
+ taskChanges &= ~CONFIG_SCREEN_SIZE;
+ }
+ }
+ if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
+ final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
+ final int newSmallest = taskConfig.smallestScreenWidthDp;
+ if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
+ taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
+ }
+ }
+ return taskChanges;
+ }
+
+ private static boolean isResizeOnlyChange(int change) {
+ return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
+ | CONFIG_SCREEN_LAYOUT)) == 0;
+ }
+
+ void relaunchActivityLocked(boolean andResume, boolean preserveWindow) {
+ if (service.mSuppressResizeConfigChanges && preserveWindow) {
+ configChangeFlags = 0;
+ return;
+ }
+
+ List<ResultInfo> pendingResults = null;
+ List<ReferrerIntent> pendingNewIntents = null;
+ if (andResume) {
+ pendingResults = results;
+ pendingNewIntents = newIntents;
+ }
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Relaunching: " + this + " with results=" + pendingResults
+ + " newIntents=" + pendingNewIntents + " andResume=" + andResume
+ + " preserveWindow=" + preserveWindow);
+ EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
+ : EventLogTags.AM_RELAUNCH_ACTIVITY, userId, System.identityHashCode(this),
+ task.taskId, shortComponentName);
+
+ startFreezingScreenLocked(app, 0);
+
+ mStackSupervisor.removeChildActivityContainers(this);
+
+ try {
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
+ "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this
+ + " callers=" + Debug.getCallers(6));
+ forceNewConfig = false;
+ mStackSupervisor.activityRelaunchingLocked(this);
+ app.thread.scheduleRelaunchActivity(appToken, pendingResults, pendingNewIntents,
+ configChangeFlags, !andResume,
+ new Configuration(service.getGlobalConfiguration()),
+ new Configuration(task.getMergedOverrideConfiguration()), preserveWindow);
+ // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
+ // pass in 'andResume' if this activity is currently resumed, which implies we aren't
+ // sleeping.
+ } catch (RemoteException e) {
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
+ }
+
+ if (andResume) {
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "Resumed after relaunch " + this);
+ }
+ results = null;
+ newIntents = null;
+ service.showUnsupportedZoomDialogIfNeededLocked(this);
+ service.showAskCompatModeDialogLocked(this);
+ } else {
+ service.mHandler.removeMessages(ActivityStack.PAUSE_TIMEOUT_MSG, this);
+ state = ActivityState.PAUSED;
+ // if the app is relaunched when it's stopped, and we're not resuming,
+ // put it back into stopped state.
+ if (stopped) {
+ getStack().addToStopping(this, true /* immediate */);
+ }
+ }
+
+ configChangeFlags = 0;
+ deferRelaunchUntilPaused = false;
+ preserveWindowOnDeferredRelaunch = false;
+ }
+
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
out.attribute(null, ATTR_ID, String.valueOf(createTime));
out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8b843e8..55066fd 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -22,10 +22,7 @@
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
-import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -33,14 +30,12 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -51,13 +46,11 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_APP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
@@ -68,7 +61,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
-import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
@@ -98,7 +90,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
@@ -109,7 +100,6 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -123,7 +113,6 @@
import android.view.Display;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -148,13 +137,11 @@
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
- private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
- private static final String TAG_SCREENSHOTS = TAG + POSTFIX_SCREENSHOTS;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
@@ -169,32 +156,28 @@
// How long we wait until giving up on the last activity to pause. This
// is short because it directly impacts the responsiveness of starting the
// next activity.
- static final int PAUSE_TIMEOUT = 500;
+ private static final int PAUSE_TIMEOUT = 500;
// How long we wait for the activity to tell us it has stopped before
// giving up. This is a good amount of time because we really need this
// from the application in order to get its saved state.
- static final int STOP_TIMEOUT = 10 * 1000;
+ private static final int STOP_TIMEOUT = 10 * 1000;
// How long we wait until giving up on an activity telling us it has
// finished destroying itself.
- static final int DESTROY_TIMEOUT = 10 * 1000;
+ private static final int DESTROY_TIMEOUT = 10 * 1000;
// How long until we reset a task when the user returns to it. Currently
// disabled.
- static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
-
- // How long between activity launches that we consider safe to not warn
- // the user about an unexpected activity being launched on top.
- static final long START_WARN_TIME = 5 * 1000;
+ private static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
// Set to false to disable the preview that is shown while a new activity
// is being started.
- static final boolean SHOW_APP_STARTING_PREVIEW = true;
+ private static final boolean SHOW_APP_STARTING_PREVIEW = true;
// How long to wait for all background Activities to redraw following a call to
// convertToTranslucent().
- static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
+ private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
// How many activities have to be scheduled to stop to force a stop pass.
private static final int MAX_STOPPING_TO_FORCE = 3;
@@ -232,18 +215,18 @@
static final int STACK_VISIBLE = 1;
// Stack is considered visible, but only becuase it has activity that is visible behind other
// activities and there is a specific combination of stacks.
- static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
+ private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
/* The various modes for the method {@link #removeTask}. */
// Task is being completely removed from all stacks in the system.
- static final int REMOVE_TASK_MODE_DESTROYING = 0;
+ private static final int REMOVE_TASK_MODE_DESTROYING = 0;
// Task is being removed from this stack so we can add it to another stack. In the case we are
// moving we don't want to perform some operations on the task like removing it from window
// manager or recents.
static final int REMOVE_TASK_MODE_MOVING = 1;
// Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new
// stack and the new stack will be on top of all stacks.
- static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
+ private static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
// The height/width divide used when fitting a task within a bounds with method
// {@link #fitWithinBounds}.
@@ -253,7 +236,7 @@
private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
final ActivityManagerService mService;
- final WindowManagerService mWindowManager;
+ private final WindowManagerService mWindowManager;
private final RecentTasks mRecentTasks;
/**
@@ -300,13 +283,6 @@
*/
ActivityRecord mResumedActivity = null;
- /**
- * This is the last activity that has been started. It is only used to
- * identify when multiple activities are started at once so that the user
- * can be warned they may not be in the activity they think they are.
- */
- ActivityRecord mLastStartedActivity = null;
-
// The topmost Activity passed to convertToTranslucent(). When non-null it means we are
// waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they
// are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the
@@ -314,7 +290,7 @@
// Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last
// background activity being drawn then the same call will be made with a true value.
ActivityRecord mTranslucentActivityWaiting = null;
- private ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>();
+ ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>();
/**
* Set when we know we are going to be calling updateConfiguration()
@@ -327,11 +303,11 @@
// Current bounds of the stack or null if fullscreen.
Rect mBounds = null;
- boolean mUpdateBoundsDeferred;
- boolean mUpdateBoundsDeferredCalled;
- final Rect mDeferredBounds = new Rect();
- final Rect mDeferredTaskBounds = new Rect();
- final Rect mDeferredTaskInsetBounds = new Rect();
+ private boolean mUpdateBoundsDeferred;
+ private boolean mUpdateBoundsDeferredCalled;
+ private final Rect mDeferredBounds = new Rect();
+ private final Rect mDeferredTaskBounds = new Rect();
+ private final Rect mDeferredTaskInsetBounds = new Rect();
long mLaunchStartTime = 0;
long mFullyDrawnStartTime = 0;
@@ -351,14 +327,8 @@
private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
private final Rect tempRect2 = new Rect();
- /**
- * Temp configs used in {@link #ensureActivityConfigurationLocked(ActivityRecord, int, boolean)}
- */
- private final Configuration mTmpGlobalConfig = new Configuration();
- private final Configuration mTmpTaskConfig = new Configuration();
-
/** Run all ActivityStacks through this */
- final ActivityStackSupervisor mStackSupervisor;
+ private final ActivityStackSupervisor mStackSupervisor;
private final LaunchingTaskPositioner mTaskPositioner;
@@ -371,7 +341,7 @@
static final int RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG =
ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
- static class ScheduleDestroyArgs {
+ private static class ScheduleDestroyArgs {
final ProcessRecord mOwner;
final String mReason;
ScheduleDestroyArgs(ProcessRecord owner, String reason) {
@@ -382,7 +352,7 @@
final Handler mHandler;
- final class ActivityStackHandler extends Handler {
+ private class ActivityStackHandler extends Handler {
ActivityStackHandler(Looper looper) {
super(looper);
@@ -427,7 +397,8 @@
Slog.w(TAG, "Activity stop timeout for " + r);
synchronized (mService) {
if (r.isInHistory()) {
- activityStoppedLocked(r, null, null, null);
+ r.activityStoppedLocked(null /* icicle */,
+ null /* persistentState */, null /* description */);
}
}
} break;
@@ -512,7 +483,7 @@
}
}
- public void getDisplaySize(Point out) {
+ void getDisplaySize(Point out) {
mActivityContainer.mActivityDisplay.mDisplay.getSize(out);
}
@@ -742,7 +713,7 @@
/**
* @param task If non-null, the task will be moved to the back of the stack.
* */
- void moveToBack(TaskRecord task) {
+ private void moveToBack(TaskRecord task) {
if (!isAttached()) {
return;
}
@@ -936,7 +907,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
+ " callers=" + Debug.getCallers(5));
setResumedActivityLocked(r, "minimalResumeActivityLocked");
- completeResumeLocked(r);
+ r.completeResumeLocked();
setLaunchTime(r);
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
"Launch completed; removing icicle of " + r.icicle);
@@ -977,7 +948,7 @@
}
}
- void clearLaunchTime(ActivityRecord r) {
+ private void clearLaunchTime(ActivityRecord r) {
// Make sure that there is no activity waiting for this to launch.
if (mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
r.displayStartTime = r.fullyDrawnStartTime = 0;
@@ -1059,50 +1030,6 @@
}
}
- public final Bitmap screenshotActivitiesLocked(ActivityRecord who) {
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivitiesLocked: " + who);
- if (who.noDisplay) {
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
- return null;
- }
-
- if (isHomeStack()) {
- // This is an optimization -- since we never show Home or Recents within Recents itself,
- // we can just go ahead and skip taking the screenshot if this is the home stack.
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tHome stack");
- return null;
- }
-
- int w = mService.mThumbnailWidth;
- int h = mService.mThumbnailHeight;
-
- if (w <= 0) {
- Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
- return null;
- }
-
- if (mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
- // When the docked stack is minimized its app windows are cropped significantly so any
- // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
- // in that case.
- if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
- return null;
- }
-
- float scale = 1f;
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
-
- // When this flag is set, we currently take the fullscreen screenshot of the activity but
- // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
- // SystemUI while keeping memory usage low.
- if (TAKE_FULLSCREEN_SCREENSHOTS) {
- w = h = -1;
- scale = mService.mFullscreenThumbnailScale;
- }
-
- return mWindowManager.screenshotApplications(who.appToken, DEFAULT_DISPLAY, w, h, scale);
- }
-
/**
* Start pausing the currently resumed activity. It is an error to call this if there
* is already an activity being paused or there is no resumed activity.
@@ -1261,57 +1188,6 @@
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
- final void activityResumedLocked(IBinder token) {
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
- r.icicle = null;
- r.haveState = false;
- }
-
- final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
- PersistableBundle persistentState, CharSequence description) {
- if (r.state != ActivityState.STOPPING) {
- Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
- mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
- return;
- }
- if (persistentState != null) {
- r.persistentState = persistentState;
- mService.notifyTaskPersisterLocked(r.task, false);
- }
- if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + r + ": " + icicle);
- if (icicle != null) {
- // If icicle is null, this is happening due to a timeout, so we
- // haven't really saved the state.
- r.icicle = icicle;
- r.haveState = true;
- r.launchCount = 0;
- r.updateThumbnailLocked(null, description);
- }
- if (!r.stopped) {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + r + " (stop complete)");
- mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
- r.stopped = true;
- r.state = ActivityState.STOPPED;
-
- mWindowManager.notifyAppStopped(r.appToken);
-
- if (getVisibleBehindActivity() == r) {
- mStackSupervisor.requestVisibleBehindLocked(r, false);
- }
- if (r.finishing) {
- r.clearOptionsLocked();
- } else {
- if (r.deferRelaunchUntilPaused) {
- destroyActivityLocked(r, true, "stop-config");
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- } else {
- mStackSupervisor.updatePreviousProcessLocked(r);
- }
- }
- }
- }
-
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
@@ -1332,7 +1208,7 @@
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
- relaunchActivityLocked(prev, prev.configChangeFlags, false,
+ prev.relaunchActivityLocked(false /* andResume */,
prev.preserveWindowOnDeferredRelaunch);
} else if (wasStopping) {
// We are also stopping, the stop request must have gone soon after the pause.
@@ -1409,7 +1285,7 @@
mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
}
- private void addToStopping(ActivityRecord r, boolean immediate) {
+ void addToStopping(ActivityRecord r, boolean immediate) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
}
@@ -1430,77 +1306,6 @@
}
}
- /**
- * Once we know that we have asked an application to put an activity in
- * the resumed state (either by launching it or explicitly telling it),
- * this function updates the rest of our state to match that fact.
- */
- private void completeResumeLocked(ActivityRecord next) {
- boolean wasVisible = next.visible;
- next.visible = true;
- if (!wasVisible) {
- // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
- mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
- }
- next.idle = false;
- next.results = null;
- next.newIntents = null;
- next.stopped = false;
-
- if (next.isHomeActivity()) {
- ProcessRecord app = next.task.mActivities.get(0).app;
- if (app != null && app != mService.mHomeProcess) {
- mService.mHomeProcess = app;
- }
- }
-
- if (next.nowVisible) {
- // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
- mStackSupervisor.reportActivityVisibleLocked(next);
- mStackSupervisor.notifyActivityDrawnForKeyguard();
- }
-
- // schedule an idle timeout in case the app doesn't do it for us.
- mStackSupervisor.scheduleIdleTimeoutLocked(next);
-
- mStackSupervisor.reportResumedActivityLocked(next);
-
- next.resumeKeyDispatchingLocked();
- mNoAnimActivities.clear();
-
- // Mark the point when the activity is resuming
- // TODO: To be more accurate, the mark should be before the onCreate,
- // not after the onResume. But for subsequent starts, onResume is fine.
- if (next.app != null) {
- next.cpuTimeAtResume = mService.mProcessCpuTracker.getCpuTimeForPid(next.app.pid);
- } else {
- next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
- }
-
- next.returningOptions = null;
-
- if (getVisibleBehindActivity() == next) {
- // When resuming an activity, require it to call requestVisibleBehind() again.
- setVisibleBehindActivity(null);
- }
- mStackSupervisor.checkReadyForSleepLocked();
- }
-
- private void setVisible(ActivityRecord r, boolean visible) {
- r.visible = visible;
- if (!visible && r.mUpdateTaskThumbnailWhenHidden) {
- r.updateThumbnailLocked(r.task.getStack().screenshotActivitiesLocked(r), null);
- r.mUpdateTaskThumbnailWhenHidden = false;
- }
- mWindowManager.setAppVisibility(r.appToken, visible);
- final ArrayList<ActivityContainer> containers = r.mChildContainers;
- for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
- ActivityContainer container = containers.get(containerNdx);
- container.setVisible(visible);
- }
- mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
- }
-
// Find the first visible activity above the passed activity and if it is translucent return it
// otherwise return null;
ActivityRecord findNextTranslucentActivity(ActivityRecord r) {
@@ -1803,7 +1608,8 @@
// is finishing, we no longer change its visibility, but we still need to take
// the screenshots if startPausingLocked decided it should be taken.
if (r.mUpdateTaskThumbnailWhenHidden) {
- r.updateThumbnailLocked(screenshotActivitiesLocked(r), null);
+ r.updateThumbnailLocked(r.screenshotActivityLocked(),
+ null /* description */);
r.mUpdateTaskThumbnailWhenHidden = false;
}
continue;
@@ -1814,14 +1620,14 @@
}
aboveTop = false;
- if (shouldBeVisible(r, behindTranslucentActivity, stackVisibleBehind,
+ if (r.shouldBeVisible(behindTranslucentActivity, stackVisibleBehind,
visibleBehind, behindFullscreenActivity)) {
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) {
- ensureActivityConfigurationLocked(r, 0, preserveWindows);
+ r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindows);
}
if (r.app == null || r.app.thread == null) {
@@ -1839,11 +1645,11 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Skipping: already visible at " + r);
- if (handleAlreadyVisible(r)) {
+ if (r.handleAlreadyVisible()) {
resumeNextActivity = false;
}
} else {
- makeVisibleIfNeeded(starting, r);
+ r.makeVisibleIfNeeded(starting);
}
// Aggregate current change flags.
configChanges |= r.configChangeFlags;
@@ -1924,33 +1730,6 @@
}
}
- /** Return true if the input activity should be made visible */
- private boolean shouldBeVisible(ActivityRecord r, boolean behindTranslucentActivity,
- boolean stackVisibleBehind, ActivityRecord visibleBehind,
- boolean behindFullscreenActivity) {
-
- if (r == null || !r.okToShowLocked()) {
- return false;
- }
-
- // mLaunchingBehind: Activities launching behind are at the back of the task stack
- // but must be drawn initially for the animation as though they were visible.
- final boolean activityVisibleBehind =
- (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == r;
-
- boolean isVisible =
- !behindFullscreenActivity || r.mLaunchTaskBehind || activityVisibleBehind;
-
- if (mService.mSupportsLeanbackOnly && isVisible && r.isRecentsActivity()) {
- // On devices that support leanback only (Android TV), Recents activity can only be
- // visible if the home stack is the focused stack or we are in split-screen mode.
- isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null
- || mStackSupervisor.isFocusedStack(this);
- }
-
- return isVisible;
- }
-
private void checkTranslucentActivityWaiting(ActivityRecord top) {
if (mTranslucentActivityWaiting != top) {
mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -1978,7 +1757,7 @@
}
if (!r.visible || r.mLaunchTaskBehind) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
- setVisible(r, true);
+ r.setVisible(true);
}
if (r != starting) {
mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
@@ -1997,7 +1776,7 @@
// keeping the screen frozen.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
try {
- setVisible(r, false);
+ r.setVisible(false);
switch (r.state) {
case STOPPING:
case STOPPED:
@@ -2047,50 +1826,6 @@
return behindFullscreenActivity;
}
- private void makeVisibleIfNeeded(ActivityRecord starting, ActivityRecord r) {
-
- // This activity is not currently visible, but is running. Tell it to become visible.
- if (r.state == ActivityState.RESUMED || r == starting) {
- if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
- "Not making visible, r=" + r + " state=" + r.state + " starting=" + starting);
- return;
- }
-
- // 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);
- // The activity may be waiting for stop, but that is no longer
- // appropriate for it.
- mStackSupervisor.mStoppingActivities.remove(r);
- mStackSupervisor.mGoingToSleepActivities.remove(r);
- } 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);
- }
- handleAlreadyVisible(r);
- }
-
- private boolean handleAlreadyVisible(ActivityRecord 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();
@@ -2576,7 +2311,7 @@
if (!next.visible || next.stopped) {
mWindowManager.setAppVisibility(next.appToken, true);
}
- completeResumeLocked(next);
+ next.completeResumeLocked();
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
@@ -2650,7 +2385,7 @@
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
- completeResumeLocked(next);
+ next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
@@ -2925,7 +2660,7 @@
* @param forceReset
* @return An ActivityOptions that needs to be processed.
*/
- final ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
+ private ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
ActivityOptions topOptions = null;
int replyChainEnd = -1;
@@ -3507,7 +3242,7 @@
return true;
}
- final void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
+ private void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
// send the result
ActivityRecord resultTo = r.resultTo;
if (resultTo != null) {
@@ -3833,8 +3568,7 @@
*
* Note: Call before #removeActivityFromHistoryLocked.
*/
- final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
- boolean setState) {
+ private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
if (mResumedActivity == r) {
mResumedActivity = null;
}
@@ -3924,7 +3658,7 @@
/**
* Perform clean-up of service connections in an activity record.
*/
- final void cleanUpActivityServicesLocked(ActivityRecord r) {
+ private void cleanUpActivityServicesLocked(ActivityRecord r) {
// Throw away any services that have been bound by this activity.
if (r.connections != null) {
Iterator<ConnectionRecord> it = r.connections.iterator();
@@ -3942,7 +3676,7 @@
mHandler.sendMessage(msg);
}
- final void destroyActivitiesLocked(ProcessRecord owner, String reason) {
+ private void destroyActivitiesLocked(ProcessRecord owner, String reason) {
boolean lastIsOpaque = false;
boolean activityRemoved = false;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -4219,7 +3953,7 @@
}
}
- boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
+ private boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
"mStoppingActivities");
@@ -4310,7 +4044,7 @@
return hasVisibleActivities;
}
- final void updateTransitLocked(int transit, ActivityOptions options) {
+ private void updateTransitLocked(int transit, ActivityOptions options) {
if (options != null) {
ActivityRecord r = topRunningActivityLocked();
if (r != null && r.state != ActivityState.RESUMED) {
@@ -4322,7 +4056,7 @@
mWindowManager.prepareAppTransition(transit, false);
}
- void updateTaskMovement(TaskRecord task, boolean toFront) {
+ private void updateTaskMovement(TaskRecord task, boolean toFront) {
if (task.isPersistable) {
task.mLastTimeMoved = System.currentTimeMillis();
// Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
@@ -4531,8 +4265,7 @@
return true;
}
- static final void logStartActivity(int tag, ActivityRecord r,
- TaskRecord task) {
+ static void logStartActivity(int tag, ActivityRecord r, TaskRecord task) {
final Uri data = r.intent.getData();
final String strData = data != null ? data.toSafeString() : null;
@@ -4561,7 +4294,8 @@
(start.task == task) ? activities.indexOf(start) : activities.size() - 1;
for (; activityIndex >= 0; --activityIndex) {
final ActivityRecord r = activities.get(activityIndex);
- updatedConfig |= ensureActivityConfigurationLocked(r, 0, preserveWindow);
+ updatedConfig |= r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+ preserveWindow);
if (r.fullscreen) {
behindFullscreen = true;
break;
@@ -4658,246 +4392,6 @@
}
}
- /**
- * Make sure the given activity matches the current configuration. Returns false if the activity
- * had to be destroyed. Returns true if the configuration is the same, or the activity will
- * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
- * correct configuration and all other bookkeeping is handled.
- */
- boolean ensureActivityConfigurationLocked(
- ActivityRecord r, int globalChanges, boolean preserveWindow) {
- if (mConfigWillChange) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check (will change): " + r);
- return true;
- }
-
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Ensuring correct configuration: " + r);
-
- // Short circuit: if the two configurations are equal (the common case), then there is
- // nothing to do.
- final Configuration newGlobalConfig = mService.getGlobalConfiguration();
- final Configuration newTaskMergedOverrideConfig = r.task.getMergedOverrideConfiguration();
- if (r.mLastReportedConfiguration.equals(newGlobalConfig)
- && r.mLastReportedOverrideConfiguration.equals(newTaskMergedOverrideConfig)
- && !r.forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration unchanged in " + r);
- return true;
- }
-
- // We don't worry about activities that are finishing.
- if (r.finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter in finishing " + r);
- r.stopFreezingScreenLocked(false);
- return true;
- }
-
- // Okay we now are going to make this activity have the new config.
- // But then we need to figure out how it needs to deal with that.
- mTmpGlobalConfig.setTo(r.mLastReportedConfiguration);
- mTmpTaskConfig.setTo(r.mLastReportedOverrideConfiguration);
- r.mLastReportedConfiguration.setTo(newGlobalConfig);
- r.mLastReportedOverrideConfiguration.setTo(newTaskMergedOverrideConfig);
-
- int taskChanges = getTaskConfigurationChanges(r, newTaskMergedOverrideConfig,
- mTmpTaskConfig);
- final int changes = mTmpGlobalConfig.diff(newGlobalConfig) | taskChanges;
- if (changes == 0 && !r.forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration no differences in " + r);
- // There are no significant differences, so we won't relaunch but should still deliver
- // the new configuration to the client process.
- r.scheduleConfigurationChanged(newTaskMergedOverrideConfig, true);
- return true;
- }
-
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration changes for " + r + " ; taskChanges="
- + Configuration.configurationDiffToString(taskChanges) + ", allChanges="
- + Configuration.configurationDiffToString(changes));
-
- // If the activity isn't currently running, just leave the new
- // configuration and it will pick that up next time it starts.
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter not running " + r);
- r.stopFreezingScreenLocked(false);
- r.forceNewConfig = false;
- return true;
- }
-
- // Figure out how to handle the changes between the configurations.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Checking to restart " + r.info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(r.info.getRealConfigChanged())
- + ", newGlobalConfig=" + newGlobalConfig
- + ", newTaskMergedOverrideConfig=" + newTaskMergedOverrideConfig);
-
- if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
- // Aha, the activity isn't handling the change, so DIE DIE DIE.
- r.configChangeFlags |= changes;
- r.startFreezingScreenLocked(r.app, globalChanges);
- r.forceNewConfig = false;
- preserveWindow &= isResizeOnlyChange(changes);
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is destroying non-running " + r);
- destroyActivityLocked(r, true, "config");
- } else if (r.state == ActivityState.PAUSING) {
- // A little annoying: we are waiting for this activity to finish pausing. Let's not
- // do anything now, but just flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is skipping already pausing " + r);
- r.deferRelaunchUntilPaused = true;
- r.preserveWindowOnDeferredRelaunch = preserveWindow;
- return true;
- } else if (r.state == ActivityState.RESUMED) {
- // Try to optimize this case: the configuration is changing and we need to restart
- // the top, resumed activity. Instead of doing the normal handshaking, just say
- // "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is relaunching resumed " + r);
-
- if (DEBUG_STATES && !r.visible) {
- Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + r
- + " called by " + Debug.getCallers(4));
- }
-
- relaunchActivityLocked(r, r.configChangeFlags, true, preserveWindow);
- } else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is relaunching non-resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, false, preserveWindow);
- }
-
- // All done... tell the caller we weren't able to keep this activity around.
- return false;
- }
-
- // Default case: the activity can handle this new configuration, so hand it over.
- // NOTE: We only forward the task override configuration as the system level configuration
- // changes is always sent to all processes when they happen so it can just use whatever
- // system level configuration it last got.
- r.scheduleConfigurationChanged(newTaskMergedOverrideConfig, true);
- r.stopFreezingScreenLocked(false);
-
- return true;
- }
-
- private int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
- Configuration oldTaskOverride) {
-
- // If we went from full-screen to non-full-screen, make sure to use the correct
- // configuration task diff, so the diff stays as small as possible.
- if (Configuration.EMPTY.equals(oldTaskOverride)
- && !Configuration.EMPTY.equals(taskConfig)) {
- oldTaskOverride = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
- }
-
- // Conversely, do the same when going the other direction.
- if (Configuration.EMPTY.equals(taskConfig)
- && !Configuration.EMPTY.equals(oldTaskOverride)) {
- taskConfig = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
- }
-
- // Determine what has changed. May be nothing, if this is a config
- // that has come back from the app after going idle. In that case
- // we just want to leave the official config object now in the
- // activity and do nothing else.
- int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */);
- // We don't want to use size changes if they don't cross boundaries that are important to
- // the app.
- if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
- final boolean crosses = record.crossesHorizontalSizeThreshold(
- oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp)
- || record.crossesVerticalSizeThreshold(
- oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp);
- if (!crosses) {
- taskChanges &= ~CONFIG_SCREEN_SIZE;
- }
- }
- if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
- final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
- final int newSmallest = taskConfig.smallestScreenWidthDp;
- if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
- taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
- }
- }
- return taskChanges;
- }
-
- private static boolean isResizeOnlyChange(int change) {
- return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
- | CONFIG_SCREEN_LAYOUT)) == 0;
- }
-
- private void relaunchActivityLocked(
- ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
- if (mService.mSuppressResizeConfigChanges && preserveWindow) {
- r.configChangeFlags = 0;
- return;
- }
-
- List<ResultInfo> results = null;
- List<ReferrerIntent> newIntents = null;
- if (andResume) {
- results = r.results;
- newIntents = r.newIntents;
- }
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Relaunching: " + r + " with results=" + results + " newIntents=" + newIntents
- + " andResume=" + andResume + " preserveWindow=" + preserveWindow);
- EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
- : EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
- r.task.taskId, r.shortComponentName);
-
- r.startFreezingScreenLocked(r.app, 0);
-
- mStackSupervisor.removeChildActivityContainers(r);
-
- try {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
- "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r
- + " callers=" + Debug.getCallers(6));
- r.forceNewConfig = false;
- mStackSupervisor.activityRelaunchingLocked(r);
- r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
- !andResume, new Configuration(mService.getGlobalConfiguration()),
- new Configuration(r.task.getMergedOverrideConfiguration()), preserveWindow);
- // Note: don't need to call pauseIfSleepingLocked() here, because
- // the caller will only pass in 'andResume' if this activity is
- // currently resumed, which implies we aren't sleeping.
- } catch (RemoteException e) {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
- }
-
- if (andResume) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "Resumed after relaunch " + r);
- }
- r.results = null;
- r.newIntents = null;
- mService.showUnsupportedZoomDialogIfNeededLocked(r);
- mService.showAskCompatModeDialogLocked(r);
- } else {
- mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- r.state = ActivityState.PAUSED;
- // if the app is relaunched when it's stopped, and we're not resuming,
- // put it back into stopped state.
- if (r.stopped) {
- addToStopping(r, true /* immediate */);
- }
- }
-
- r.configChangeFlags = 0;
- r.deferRelaunchUntilPaused = false;
- r.preserveWindowOnDeferredRelaunch = false;
- }
-
boolean willActivityBeVisibleLocked(IBinder token) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
@@ -5051,7 +4545,7 @@
}
}
- public void unhandledBackLocked() {
+ void unhandledBackLocked() {
final int top = mTaskHistory.size() - 1;
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
if (top >= 0) {
@@ -5341,7 +4835,7 @@
task.getOverrideConfiguration(), task.mResizeMode, r.isAlwaysFocusable(),
task.isHomeTask(), r.appInfo.targetSdkVersion, r.mRotationAnimationHint,
task.isOnTopLauncher());
- r.mLastReportedOverrideConfiguration.setTo(task.getMergedOverrideConfiguration());
+ r.onOverrideConfigurationSent();
}
void moveToFrontAndResumeStateIfNeeded(
@@ -5395,7 +4889,7 @@
mWindowManager.setAppTask(r.appToken, task.taskId, mStackId, bounds,
task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
task.isOnTopLauncher());
- r.mLastReportedOverrideConfiguration.setTo(task.getMergedOverrideConfiguration());
+ r.onOverrideConfigurationSent();
}
public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index b98bc48..cd7481c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1619,7 +1619,7 @@
// We'll update with whatever configuration it now says
// it used to launch.
if (config != null) {
- r.mLastReportedConfiguration.setTo(config);
+ r.setLastReportedConfiguration(config);
}
// We are now idle. If someone is waiting for a thumbnail from
@@ -2255,11 +2255,9 @@
if (updatedConfig) {
final ActivityRecord r = task.topRunningActivityLocked();
if (r != null) {
- final ActivityStack stack = r.getStack();
- kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
+ kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
if (!deferResume) {
-
// All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
if (!kept) {
@@ -2884,12 +2882,12 @@
}
// Called when WindowManager has finished animating the launchingBehind activity to the back.
- void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
+ private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
final TaskRecord task = r.task;
final ActivityStack stack = task.getStack();
r.mLaunchTaskBehind = false;
- task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
+ task.setLastThumbnailLocked(r.screenshotActivityLocked());
mRecentTasks.addLocked(task);
mService.notifyTaskStackChangedLocked();
mWindowManager.setAppVisibility(r.appToken, false);
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 32790fc..bfc0456 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -385,7 +385,8 @@
}
if (starting != null) {
- stack.ensureActivityConfigurationLocked(starting, 0, false);
+ starting.ensureActivityConfigurationLocked(0 /* globalChanges */,
+ false /* preserveWindow */);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
stack.ensureActivitiesVisibleLocked(starting, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index af0e926..b9f434a 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -974,11 +974,11 @@
return null;
}
- public TaskThumbnail getTaskThumbnailLocked() {
+ TaskThumbnail getTaskThumbnailLocked() {
if (mStack != null) {
final ActivityRecord resumedActivity = mStack.mResumedActivity;
if (resumedActivity != null && resumedActivity.task == this) {
- final Bitmap thumbnail = mStack.screenshotActivitiesLocked(resumedActivity);
+ final Bitmap thumbnail = resumedActivity.screenshotActivityLocked();
setLastThumbnailLocked(thumbnail);
}
}
@@ -987,7 +987,7 @@
return taskThumbnail;
}
- public void removeTaskActivitiesLocked() {
+ void removeTaskActivitiesLocked() {
// Just remove the entire task.
performClearTaskAtIndexLocked(0);
}